diff --git a/docs/icgc.html b/docs/icgc.html index 7d82f06..a3451b5 100644 --- a/docs/icgc.html +++ b/docs/icgc.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/online-ca.html b/docs/online-ca.html index bde4678..4b7830f 100644 --- a/docs/online-ca.html +++ b/docs/online-ca.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/online-es.html b/docs/online-es.html index 2100e2b..c39ab7b 100644 --- a/docs/online-es.html +++ b/docs/online-es.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/online.html b/docs/online.html index 7b27aae..60bc365 100644 --- a/docs/online.html +++ b/docs/online.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/plugin_github.html b/docs/plugin_github.html index 835701a..ee5a462 100644 --- a/docs/plugin_github.html +++ b/docs/plugin_github.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/plugin_icgc.html b/docs/plugin_icgc.html index c886a76..93e6ff8 100644 --- a/docs/plugin_icgc.html +++ b/docs/plugin_icgc.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/plugin_issues.html b/docs/plugin_issues.html index be0404e..0ea6862 100644 --- a/docs/plugin_issues.html +++ b/docs/plugin_issues.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/docs/plugin_qgis.html b/docs/plugin_qgis.html index 59818b3..6f477a6 100644 --- a/docs/plugin_qgis.html +++ b/docs/plugin_qgis.html @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/geofinder3/geofinder.py b/geofinder3/geofinder.py index d0ad8c2..482d0d3 100644 --- a/geofinder3/geofinder.py +++ b/geofinder3/geofinder.py @@ -245,24 +245,45 @@ def get_cadastral_ref(self, text): return cadastral_ref - def find_rectangle_coordinates(self, west, north, east, south, epsg): + def find_rectangle_coordinates(self, west, north, east, south, epsg, add_rect_if_empty=True, show_log=True): """ Returns a list with a dictionary with the coordinates of the rectangle """ - print(u"Rectangle: %s %s %s %s EPSG:%s" % (west, north, east, south, epsg)) + if show_log: + print(u"Rectangle: %s %s %s %s EPSG:%s" % (west, north, east, south, epsg)) + + # Find central point (exclude last result: "Point x, y") + central_x = west + (west-east) / 2.0 + central_y = south + (north-south) / 2.0 dicts_list = [{ - 'nom':'Rectangle (%s %s %s %s)' % (west, north, east, south), 'west': float(west), 'north': float(north), 'east': float(east), 'south': float(south), - 'epsg': int(epsg) - }] + **point_dict + } for point_dict in self.find_point_coordinate(central_x, central_y, epsg, add_point_if_empty=False)] + # If not results, inject an entry with point + if not dicts_list and add_rect_if_empty: + dicts_list.append({ + 'nom':'Rectangle (%s %s %s %s)' % (west, north, east, south), + 'idTipus': u'', + 'nomTipus': u'', + 'nomMunicipi': u'', + 'nomComarca': u'', + 'x': central_x, + 'y': central_y, + 'west': float(west), + 'north': float(north), + 'east': float(east), + 'south': float(south), + 'epsg': int(epsg) + }) return dicts_list - def find_point_coordinate(self, x, y, epsg): + def find_point_coordinate(self, x, y, epsg, add_point_if_empty=True, show_log=True): """ Returns a list of dictionaries with the sites found at the indicated point """ - print(u"Coordinate: %s %s EPSG:%s" % (x, y, epsg)) + if show_log: + print(u"Coordinate: %s %s EPSG:%s" % (x, y, epsg)) # We convert the coordinates to ETRS89 UTM31N to do the query nom = "Point: %s %s (EPSG:%s)" % (x, y, epsg), @@ -292,13 +313,32 @@ def find_point_coordinate(self, x, y, epsg): 'y': y, 'epsg': epsg } for label_adrecaInversa, res_dict in res_tuple_list if res_dict and label_adrecaInversa == 'adrecaInversa'] + # If not results, inject an entry with point + if not dicts_list and add_point_if_empty: + dicts_list.append({ + 'nom': "Punt %s %s" % (x, y), + 'idTipus': u'', + 'nomTipus': u'', + 'nomMunicipi': u'', + 'nomComarca': u'', + 'x': x, + 'y': y, + 'epsg': epsg + }) return dicts_list def transform_point(self, x, y, source_epsg, destination_epsg): + # EN GDAL 3 al convertir una coordenada a WGS84 gira x<->y per evitar-ho canviar WGS84 oer CRS84!! source_crs = osr.SpatialReference() source_crs.ImportFromEPSG(int(source_epsg)) + if source_epsg == 4326: + source_crs.SetWellKnownGeogCS("CRS84") + destination_crs = osr.SpatialReference() destination_crs.ImportFromEPSG(int(destination_epsg)) + if destination_epsg == 4326: + destination_crs.SetWellKnownGeogCS("CRS84") + ct = osr.CoordinateTransformation(source_crs, destination_crs) destination_x, destination_y, _h = ct.TransformPoint(x, y) return destination_x, destination_y @@ -542,7 +582,7 @@ def find_placename(self, text): def is_rectangle(self, dict_list): """ Check if dict_list is of rectangle type """ - return len(dict_list) == 1 and dict_list[0]['nom'].startswith("Rectangle") + return len(dict_list) == 1 and dict_list[0].get("west", None) def get_rectangle(self, dict_list): """ Returns rectangle coordinates of dict_list type rectangle. diff --git a/i18n/openicgc_ca.ts b/i18n/openicgc_ca.ts index d78bb1c..872cd53 100644 --- a/i18n/openicgc_ca.ts +++ b/i18n/openicgc_ca.ts @@ -4,42 +4,42 @@ OpenICGC - + Spatial search Cerca espacial - + Find Cercar - + Background maps Mapes de fons - + Delete background maps Esborrar mapes de fons - + Transparence Transparència - + Reload Open ICGC Recarregar Open ICGC - + Error, location without coordinates Error, localització sense coordenades - + Find: Address: municipality, street number or vice versa Barcelona, Aribau 86 @@ -110,137 +110,137 @@ 13077A018000390000FP - + Time series Sèries temporals - + About Open ICGC Sobre Open ICGC - + Help Ajuda - + Select download folder Seleccionar carpeta de descàrregues - + Name Nom - + Type Tipus - + Municipality Municipi - + Region Comarca - + Municipalities Municipis - + Counties Comarques - + Provinces Províncies - + Color orthophoto Ortofoto color - + [TS] Color orthophoto [ST] Ortofoto color - + Infrared orthophoto Ortofoto infraroja - + [TS] Infrared orthophoto [ST] Ortofoto infraroja - + Download Descàrregues - + Open download folder Obrir carpeta de descàrregues - + Paint styles for selected layers Estil de pintat de les capes seleccionades - + Desaturate raster layer Desaturació de capa ràster - + Reference %s Referència %s - + Download map area Descarregar àrea de mapa - + Minimum download rect side not reached (%d m) Mida mínima de descàrrega no aconseguida (%d m costat) - + Maximum download area reached (%s m%s) Àrea màxima de descàrrega sobrepassada (%s m%s) - + Change DB/geoPackage style Canviar estil de geoPackage / base de dades - + Error downloading file or selection is out of reference area Error descarregant el fitxer o la selecció està fora de l'àrea de referència - + You must write any text Cal escriure algun text - + Data type: %s (%s) Rectangle: @@ -263,7 +263,7 @@ Carpeta de descàrregues: Nom d'arxiu (%s): - + Data type: %s (%s) Point: @@ -286,7 +286,7 @@ Carpeta de descàrregues: Nom d'arxiu (%s): - + Data type: %s (%s) Point: @@ -309,47 +309,47 @@ Carpeta de descàrregues: Nom d'arxiu (%s): - + Error, can't find product %s as available to download Error, no s'ha trobat el producte %s per descarregar - + Find place names and adresses Cercar topònims i adreces - + Area Àrea - + County Comarca - + Catalonia Catalunya - + Available data Dades disponibles - + Download tool Eina de descàrrega - + Download point Descarregar punt - + Data type: %s (%s) Zone: @@ -368,7 +368,7 @@ Carpeta de descàrregues: Arxiu (%s): - + Select the type of download and then use the download tool to mark a point or area of interest, enter a rectangle coordinates or select a polygons layer @@ -381,42 +381,42 @@ coordenades d'un rectàngle o selecciona una capa de polígons Tipus de descàrrega: - + Selected: Seleccionat: - + Cartographic series Talls cartogràfics - + Select an area Selecciona una àrea - + Select municipality Selecciona un municipi - + Select county Selecciona una comarca - + Unknow, service unavailable Desconegut, servei no accessible - + Available products list Llista de productes disponibles - + Linkable products: - %s @@ -429,74 +429,74 @@ Productes descarregables: - %s - + Open ICGC Toolbar Barra d'eines d'Open ICGC - + Add height highlighting Afegir ressaltat d'alçades - + Height highlighting Ressaltat d'alçades - + Warning: Atenció: - + QGIS version warnings Alertes de la versió de QGIS - + Download plugin Descarregar plugin - + Update available: v%s Actualització disponible: %s - + You can modify the brightness of the "Height hightlghting" layer to adjust the display to your background layer Pots modificar la brillantor de la capa "Ressaltat d'alçades" per ajustar la visualització a la teva capa de fons - + %s serie Tall %s - + QGIS plugin repository Repositori de connectors de QGIS - + Software Repository Repositori de codi - + Report an issue Reportar una incidència - + Send us an email Envia'ns un email - + Your QGIS version is %s. In versions of QGIS lower than 3.10.4 http files may not load correctly. Affected products will be disabled. @@ -511,7 +511,7 @@ En versions de QGIS inferiors a 3.4.0, els arxiu geopackage poden no carregar co Actualitza la versió de QGIS si és possible. - + ICGC products are generated in EPSG 25831, loading them into a project with EPSG %s could cause display problems, download problems, or increased load time. Do you want change the project coordinate system to EPSG 25831? @@ -520,546 +520,546 @@ Do you want change the project coordinate system to EPSG 25831? Vols canviar el sistema de coordenades del projecte a EPSG 25831? - + What's new Novetats - + Cartographic and Geological Institute of Catalonia web Web de l'Institut Cartogràfic i Geològic de Catalunya - + Color orthophoto 25cm 1:2,500 Ortofoto color 25cm 1:2.500 - + Color orthophoto 50cm 1:5,000 Ortofoto color 50cm 1:5.000 - + Color orthophoto 2.5m 1:25,000 Ortofoto color 2.5m 1:25.000 - + Infrared orthophoto 25cm 1:2,500 Ortofoto infraroja 25cm 1:2.500 - + Infrared orthophoto 50cm 1:5,000 Ortofoto infraroja 50cm 1:5.000 - + Infrared orthophoto 2.5m 1:25,000 Ortofoto infraroja 2.5m 1:25.000 - + Topographic map 1:25,000 Mapa topogràfic 1:25.000 - + Topographic map 1:50,000 Mapa topogràfic 1:50.000 - + Topographic map 1:100,000 Mapa topogràfic 1:1.00.000 - + Topographic map 1:250,000 Mapa topogràfic 1:250.000 - + Topographic map 1:500,000 Mapa topogràfic 1:500.000 - + Topographic map 1:1,000,000 Mapa topogràfic 1:1.000.000 - + Topographic map 1:2,000,000 Mapa topogràfic 1:2.000.000 - + Topographic cartography 1:1,000 Cartografia topogràfica 1:1.000 - + Territorial topographic referential Referencial topogràfic territorial - + Land cover map Mapa de cobertes del sòl - + Digital terrain model 2m Model d'elevacions del terreny 2m - + Digital terrain model 5m Model d'elevacions del terreny 5m - + Geological map 1:250,000 Mapa geològic 1:250.000 - + %s vectorial data %s dades vectorials - + %s raster data %s dades ràster - + Territorial topographic referential 3D Referencial topogràfic territorial 3D - + NDVI color (temporal serie) NDVI color (sèrie temporal) - + [TS] NDVI color [ST] NDVI color - + NDVI (temporal serie) NDVI (sèrie temporal) - + [TS] NDVI [ST] NDVI - + File type %s is unsupported by QGIS Do you want try open downloaded file in a external viewer? El tipus de fitxer %s no està suportat per QGIS Vols intentar obrir el fitxer descarregat amb un visor extern? - + Color orthophoto %s (provisional) Ortofoto color %s (provisional) - + Color orthophoto %s (rectification without corrections) Ortofoto color %s (rectificació sense correccions) - + Color orthophoto %s (temporal serie) Ortofoto color %s (sèrie temporal) - + Color orthophoto (annual serie) Ortofoto color (sèrie anual) - + Satellite color orthophoto (monthly serie) Ortofoto color satèl·lit (sèrie mensual) - + Infrared orthophoto %s (provisional) Ortofoto infraroja %s (provisional) - + Infrared orthophoto %s (rectification without corrections) Ortofoto infraroja %s (rectificació sense correccions) - + Infrared orthophoto %s (temporal serie) Ortofoto infraroja %s (sèrie temporal) - + Infrared orthophoto (annual serie) Ortofoto infraroja (sèrie anual) - + Satellite infrared orthophoto (monthly serie) Ortofoto infraroja satèl·lit (sèrie mensual) - + Shading DTM layer Ombrejat de capa MET - + The selected area is outside Catalonia L'àrea seleccionada és fora de Catalunya - + You must select a DTM layer S'ha de seleccionar una capa de MET - + You can modify the angle of the sun in the layer simbology Es pot modificar l'angle del sol en la simbologia de la capa - + [AS] Color orthophoto [SA] Ortofoto color - + [MS] Satellite color orthophoto [SM] Ortofoto color satèl·lit - + [AS] Infrared orthophoto [SA] Ortofoto infraroja - + [MS] Satellite infared orthophoto [SM] Ortofoto infraroja satèl·lit - + Geological map 1:50,000 Mapa geològic 1:50.000 - + Municipal capitals Caps de municipi - + Vegueries Vegueries - + Administrative divisions Divisions administratives - + Territorial topographic referential %s (temporal serie) Referencial topogràfic territorial %s (sèrie temporal) - + [TS] Territorial topographic referential [ST] Referencial topogràfic territorial - + Administrative divisions (raster pyramid) Divisions administratives (Piràmide ràster) - + The download file could not be opened No s'ha pogut obrir l'arxiu descarregat - + raster ràster - + vector vector - + Photo library Fototeca - + Photograms Fotogrames - + Photo: %s Foto: %s - + Photo query: %s Consulta fotos: %s - + Search photograms Cercar fotogrames - + Coord %s %s Coord %s %s - + It exists a previous photo search. Do you want close it? Existeix un cerca de fotogrames prèvia. Vols tancar-la? - + Search photograms interactively Cercar fotogrames interactivament - + Search photograms by coordinates Cercar fotogrames per coordenada - + Photograms search tool Eina de cerca de fotogrames - + Select a point Selecciona un punt - + Enter an x y value in the project coordinate system or add the corresponding EPSG code in the following format: "429393.19 4580194.65" or "429393.19 4580194.65 EPSG:25831" or "EPSG:25831 429393.19 4580194.65" Introdueix valors x y en el sistema de coordenades del projecte o afegeix el corresponent codi EPSG en el següent format: "429393.19 4580194.65" o "429393.19 4580194.65 EPSG:25831" o "EPSG:25831 429393.19 4580194.65" - + Flight code Codi de vol - + Flight date Data de vol - + Flight year Any de vol - + Image filename Arxiu d'imatge - + Image width Amplada d'imatge - + Image height Alçada d'imatge - + Image channels Canals d'imatge - + Image bits PPC Bits PPC d'imatge - + Color type Tipus de color - + Strip Passada - + Camera Càmera - + Focal Length Distància focal - + Ground sampling distance Mida de píxel - + Scale Escala - + Flying height Alçada de vol - + Mean ground height Alçada mitja del terra - + View type Tipus de vista - + Northing Nord - + Easting Est - + EPSG code Codi EPSG - + Omega Omega - + Phi Phi - + Kappa Kappa - + Photo in strip Fotograma dins la passada - + Spain Espanya - + IGN topographic Topogràfic IGN - + PNOA orthophoto Ortofoto PNOA - + Andorra Andorra - + Andorra topographic 1:25,000 1989 Andorra topogràfic 1:25.000 1989 - + Andorra topographic 1:50,000 1987 Andorra topogràfic 1:50.000 1987 - + Andorra orthophoto 1:5,000 2003 Andorra ortofoto 1:5.000 2003 - + Andorra Infrared orthophoto 1:5,000 2003 Andorra ortofoto infraroja 1:5.000 2003 - + Andorra orthophoto 1:500-1,000 20cm 2008 Andorra ortofoto 1:500-1.000 20cm 2003 - + World Mon - + NASA blue marble Nasa blue marble - + Minimum download rect side not reached (%d px) Mida mínima de descàrrega no aconseguida (%d px costat) - + Maximum download area reached (%s px%s) Àrea màxima de descàrrega sobrepassada (%s px%s) - + Area coordinates Coordenades de l'àrea - + Enter west, north, east, south values in the project coordinates system or add the corresponding EPSG code in the following format: "429393.19 4580194.65 429493.19 4580294.65" or "429393.19 4580194.65 429493.19 4580294.65 EPSG:25831" or @@ -1070,22 +1070,22 @@ Vols intentar obrir el fitxer descarregat amb un visor extern? "EPSG:25831 429393.19 4580194.65 429493.19 4580294.65" - + Territorial topographic referential volume Referencial topogràfic territorial volum - + Selected layer polygons Polígons selecionats en una capa - + You must activate a vector layer with one or more selected polygons Cal activar una capa vectorial amb un o més polígons seleccionats - + Data type: %s (%s) Polygon area: @@ -1104,67 +1104,62 @@ Carpeta de descàrregues: Nom d'arxiu (%s): - + Your polygons have too many points: %d maximum %d El polígons tenen massa punts: %d màxim %d - + Topographic map (topographical pyramid) Mapa topogràfic (piràmide topogràfica) - + Land cover map (temporal serie) Mapa de cobertes del sòl (sèrie temporal) - + [TS] Land cover map [ST] Mapa de cobertes del sòl - + Digital Terrain Model %s Model d'elevacions del terreny %s - + Incorrect coordinates format Format de coordenades incorrecte - + Instamaps pyramid Piràmide Instamaps - + Cadastral registry Cadastre - + Geological map 1:25,000 (GT I) Mapa geològic 1:25.000 (GT I) - + Geological map for the prevention of geological hazards 1:25,000 (GT VI) Mapa geològic per a la prevenció dels riscos geològics 1:25.000 (GT VI) - + Report photo bug Reportar error de fotograma - - Problem description: - Descripció del problema: - - - + Thanks for reporting an error in photogram: %s @@ -1175,7 +1170,7 @@ We try to fix it as soon as possible Intentarem corregir-ho el més aviat possible - + Before reporting an error, bear in mind that the position of photograms is an approximation i will never completely fit the underlying cartography, since no terrain model has been used to project the imatge against. Furthermore, changes in instrumenation over time (wheter GPS is used or not, scanning and photogrammetric workflow) account for a very limited precision in positioning. Only large displacements in position (for example, an element that should appear near the center does not appear) or if there is an error in rotation (eg. the sea appears in the northern part of a photo). @@ -1188,156 +1183,241 @@ Només cal considerar error d’ubicació si el fotograma està molt desplaçat Vols continuar? - + You must select one photogram Cal seleccionar un fotograma + + + Keep scale + Mantenir escala + + + + Anaglyph + Anaglif + + + + Inverted stereo + Estèreo invertit + + + + Analog + Analògic + + + + Centered anaglyph photogram + Fotograma anaglif central + + + + [AS] Centered anaglyph phootogram + [SA] Fotograma anaglif central + + + + Centered rectified photogram (annual serie) + Fotograma rectificat central (sèrie anual) + + + + [AS] Centered rectified photogram + [SA] Fotograma rectificat central + + + + Centered photogram (annual serie) + Fotograma central (sèrie anual) + + + + [AS] Centered photogram + [SA] Fotograma central + + + + Centered anaglyph photogram %s (annual serie) + Fotograma anaglif central %s (sèrie anual) + + + + This layer renders only the most centered photogram in the map view, you can zoom in for continuous navigation. Please note that current year may not have full photogram coverage + Mostra només el fotograma més centrat en la vista mapa, pots apropar-te per obtenir una navegació contínua. L'any actual pot no tenir una cobertura completa + + + + Photo: %s +Flight code: %s +Date: %s +Resolution: %.2fm + +Problem description: + Foto: %s +Codi de vol: %s +Data: %s +Resolució: %.2fm + +Descripció del problema: + + + + Search photograms by name + Cercar fotogrames per nom + + + + Photogram name: + Nom de fotograma: + PhotoSearchSelectionDialog - + Years range Rang d'anys - + Resolution Resolució - + All Totes - + Very high (< 15 cm/px) Molt alta (<15 cm/px) - + High (approx. 25 cm/px) Alta (aprox. 25 cm/px) - + Medium (approx. 50 cm/px) Mitja (aprox. 50 cm/px) - + Low (> 60 cm/px) Baixa (> 60 cm/px) - + Photogram Fotograma - + Date Data - + m/px m/px - + Information Informació - + Year: %s Any: %s - + Photograms: %s Fotogrames: %s - + Download Descarregar - + Request certificate Sol·licitar certificat - + Report photo bug Reportar error en fotograma - + View Visualitzar - + Request certificate Sol·licitar certificat - + Request scan Sol·licitar escaneig - + Request scan Sol·licitar escaneig - + Adjust brightness Ajustar brillantor - + Adjust brightness Ajustar brillantor - + Unavailable or lost No disponible o perdut - + No publishable No publicable - + Scan required Escaneig requerit - + Available Disponible - + Note: Photograms locations are approximate Nota: La ubicació dels fotogrames és aproximada - + When photograms list is focused you can use up and down cursor keys to select current photo, left and right keys to select current year and @@ -1347,5 +1427,35 @@ les tecles amunt i avall per seleccionar el fotograma actiu, les tecles esquerra i dreta per seleccionar l'any actiu i la tecla intro per visualitzar la foto + + + Rectified photogram "on the fly" + Fotograma rectificat "al vol" + + + + Anaglyph photogram "on the fly" + Fotograma anaglif "al vol" + + + + View type + Tipus de vista + + + + Parallax: %+d%% + Paral·laxi: %+d%% + + + + Inverted stereo + Estèreo invertit + + + + Photogram nominal orientation + Fotograma orientació nominal + diff --git a/i18n/openicgc_es.ts b/i18n/openicgc_es.ts index 0f6a0c8..af735fa 100644 --- a/i18n/openicgc_es.ts +++ b/i18n/openicgc_es.ts @@ -4,42 +4,42 @@ OpenICGC - + Spatial search Búsqueda espacial - + Find Buscar - + Background maps Mapas de fondo - + Delete background maps Borrar mapas de fondo - + Transparence Trasparencia - + Reload Open ICGC Recargar Open ICGC - + Error, location without coordinates Error, localización sin coordenadas - + Find: Address: municipality, street number or vice versa Barcelona, Aribau 86 @@ -110,137 +110,137 @@ 13077A018000390000FP - + Time series Series temporales - + About Open ICGC Acerca de Open ICGC - + Help Ayuda - + Select download folder Selección de carpeta de descargas - + Name Nombre - + Type Tipo - + Municipality Municipio - + Region Comarca - + Municipalities Municipios - + Counties Comarcas - + Provinces Provincias - + Color orthophoto Ortofoto color - + [TS] Color orthophoto [ST] Ortofoto color - + Infrared orthophoto Ortofoto infrarroja - + [TS] Infrared orthophoto [ST] Ortofoto infrarroja - + Download Descargas - + Open download folder Abrir carpeta de descargas - + Paint styles for selected layers Estilo de pintado de las capas seleccionadas - + Desaturate raster layer Desaturar capa raster - + Reference %s Referencia %s - + Download map area Descargar área de mapa - + Minimum download rect side not reached (%d m) Tamaño mínimo de descarga no alcanzado (%d m por lado) - + Maximum download area reached (%s m%s) Máxima área de descarga alcanzada (%s m%s) - + Change DB/geoPackage style Cambiar estilo de geoPackage / base de datos - + Error downloading file or selection is out of reference area Error descargando el fitchero o la selección está fuera del área de referencia - + You must write any text Debes escribir algun texto - + Data type: %s (%s) Rectangle: @@ -263,7 +263,7 @@ Carpeta de descargas: Nombre de archivo (%s): - + Data type: %s (%s) Point: @@ -286,7 +286,7 @@ Carpeta de descargas: Nombre de archivo (%s): - + Data type: %s (%s) Point: @@ -309,47 +309,47 @@ Carpeta de descargas: Nombre de archivo (%s): - + Error, can't find product %s as available to download Error, no se ha encontrado el producto %s a descargar - + Find place names and adresses Buscar topónimos y direcciones - + Area Área - + County Comarca - + Catalonia Cataluña - + Available data Datos disponibles - + Download tool Herramienta de descarga - + Download point Descarga puntual - + Data type: %s (%s) Zone: @@ -368,7 +368,7 @@ Carpeta de descargas: Archivo (%s): - + Select the type of download and then use the download tool to mark a point or area of interest, enter a rectangle coordinates or select a polygons layer @@ -381,42 +381,42 @@ coordenadas de un rectángulo o selecciona una capa de polígonos Tipo de descarga: - + Selected: Seleccionado: - + Cartographic series Cortes cartográficos - + Select an area Selecciona un área - + Select municipality Selecciona un municipio - + Select county Selecciona una comarca - + Unknow, service unavailable Desconocido, servicio no accesible - + Available products list Lista de productos disponibles - + Linkable products: - %s @@ -429,74 +429,74 @@ Productos descargables: - %s - + Open ICGC Toolbar Barra de herramientas de Open ICGC - + Add height highlighting Añadir resaltado de alturas - + Height highlighting Resaltado de alturas - + Warning: Atención: - + QGIS version warnings Alertas de la versión de QGIS - + Download plugin Descargar plugin - + Update available: v%s Actualización disponible: v%s - + You can modify the brightness of the "Height hightlghting" layer to adjust the display to your background layer Puedes modificar el brillo de la capa "Resaltado de alturas" para ajustar la visualización a tu capa de fondo - + %s serie Corte %s - + QGIS plugin repository Repositorio de conectores de QGIS - + Software Repository Repositorio de código - + Report an issue Reportar una incidencia - + Send us an email Envíanos un email - + Your QGIS version is %s. In versions of QGIS lower than 3.10.4 http files may not load correctly. Affected products will be disabled. @@ -511,7 +511,7 @@ En versiones de QGIS inferiores a 3.4.0 los archivos geopackage pueden no cargar Actualiza tu versión de QGIS si es posible. - + ICGC products are generated in EPSG 25831, loading them into a project with EPSG %s could cause display problems, download problems, or increased load time. Do you want change the project coordinate system to EPSG 25831? @@ -520,551 +520,551 @@ Do you want change the project coordinate system to EPSG 25831? ¿Quieres cambiar el sistema de coordenadas del projecto a EPSG 25831? - + What's new Novedades - + Cartographic and Geological Institute of Catalonia web Web del Instituto Cartográfico y Geológico de Cataluña - + Color orthophoto 25cm 1:2,500 Ortofoto color 25cm 1:2.500 - + Color orthophoto 50cm 1:5,000 Ortofoto color 50cm 1:5.000 - + Color orthophoto 2.5m 1:25,000 Ortofoto color 2.5m 1:25.000 - + Infrared orthophoto 25cm 1:2,500 Ortofoto infrarroja 25cm 1:2.500 - + Infrared orthophoto 50cm 1:5,000 Ortofoto infrarroja 50cm 1:5.000 - + Infrared orthophoto 2.5m 1:25,000 Ortofoto infrarroja 2.5m 1:25.000 - + Topographic map 1:25,000 Mapa topográfico 1:25.000 - + Topographic map 1:50,000 Mapa topográfico 1:50.000 - + Topographic map 1:100,000 Mapa topográfico 1:100.000 - + Topographic map 1:250,000 Mapa topográfico 1:250.000 - + Topographic map 1:500,000 Mapa topográfico 1:500.000 - + Topographic map 1:1,000,000 Mapa topográfico 1:1.000.000 - + Topographic map 1:2,000,000 Mapa topográfico 1:2.000.000 - + Topographic cartography 1:1,000 Cartografía topográfica 1:1.000 - + Territorial topographic referential Referencial topográfico territorial - + Land cover map Mapa de cubiertas del suelo - + Digital terrain model 2m Modelo de elevaciones del terreno 2m - + Digital terrain model 5m Modelo de elevaciones del terreno 5m - + Geological map 1:250,000 Mapa geológico 1:250.000 - + %s vectorial data %s datos vectoriales - + %s raster data %s datos ráster - + Geological map for the prevention of geological hazards 1:25,000 (GT VI) Mapa geológico para la prevención de los riesgos geológicos 1:25.000 (GT VI) - + Territorial topographic referential 3D Referencial topográfico territorial 3D - + NDVI color (temporal serie) NDVI color (serie temporal) - + [TS] NDVI color [ST] NDVI color - + NDVI (temporal serie) NDVI (serie temporal) - + [TS] NDVI [ST] NDVI - + File type %s is unsupported by QGIS Do you want try open downloaded file in a external viewer? El tipo de fichero %s no está soportado por QGIS ¿Quieres intentar abrir el fichero descargado en un visor externo? - + Color orthophoto %s (provisional) Ortofoto color %s (provisional) - + Color orthophoto %s (rectification without corrections) Ortofoto color %s (rectificación sin correcciones) - + Color orthophoto %s (temporal serie) Ortofoto color %s (serie temporal) - + Color orthophoto (annual serie) Ortofoto color (serie anual) - + Satellite color orthophoto (monthly serie) Ortofoto color satélite (serie mensual) - + Infrared orthophoto %s (provisional) Ortofoto infrarroja %s (provisional) - + Infrared orthophoto %s (rectification without corrections) Ortofoto infrarroja %s (rectificación sin correcciones) - + Infrared orthophoto %s (temporal serie) Ortofoto infrarroja %s (serie temporal) - + Infrared orthophoto (annual serie) Ortofoto infrarroja %s (serie anual) - + Satellite infrared orthophoto (monthly serie) Ortofoto infrarroja setélite (serie mensual) - + Shading DTM layer Sombreado de capa MET - + The selected area is outside Catalonia El área seleccionada se encuentra fuera de Cataluña - + You must select a DTM layer Se ha de seleccionar una capa MET - + You can modify the angle of the sun in the layer simbology Se puede modificar el ángulo del sol desde la simbología de la capa - + [AS] Color orthophoto [SA] Ortofoto color - + [MS] Satellite color orthophoto [SM] Ortofoto color satélite - + [AS] Infrared orthophoto [SA] Ortofoto infrarroja - + [MS] Satellite infared orthophoto [SM] Ortofoto infrarroja satélite - + Geological map 1:50,000 Mapa geológico 1:50.000 - + Municipal capitals Capitales de municipio - + Vegueries Veguerías - + Administrative divisions Divisiones administrativas - + Territorial topographic referential %s (temporal serie) Referencial topográfico territorial %s (Serie temporal) - + [TS] Territorial topographic referential [ST] Referencial topográfico territorial - + Administrative divisions (raster pyramid) Divisiones administrativas (pirámide raster) - + The download file could not be opened No se ha podido abrir el archivo descargado - + raster raster - + vector vector - + Photo library Fototeca - + Photograms Fotogramas - + Photo: %s Foto: %s - + Photo query: %s Consulta fotogramas: %s - + Search photograms Buscar fotogramas - + Coord %s %s Coord %s %s - + It exists a previous photo search. Do you want close it? Existe una búsqueda de fotogramas previa. ¿Quieres cerrarla? - + Search photograms interactively Buscar fotogramas interactivamente - + Search photograms by coordinates Buscar fotogramas por coordenada - + Photograms search tool Herramienta de búsqueda de fotogramas - + Select a point Selecciona un punto - + Enter an x y value in the project coordinate system or add the corresponding EPSG code in the following format: "429393.19 4580194.65" or "429393.19 4580194.65 EPSG:25831" or "EPSG:25831 429393.19 4580194.65" Introduce valores x y en el sistema de coordenadas del proyecto o añade el correspondiente código EPSG en el siguiente formato: "429393.19 4580194.65" o "429393.19 4580194.65 EPSG:25831" o "EPSG:25831 429393.19 4580194.65" - + Flight code Código de vuelo - + Flight date Fecha de vuelo - + Flight year Año de vuelo - + Image filename Archivo de imagen - + Image width Anchura de imagen - + Image height Altura de imagen - + Image channels Canales de imagen - + Image bits PPC Bits PPC de imagen - + Color type Tipo de color - + Strip Pasada - + Camera Cámara - + Focal Length Distancia focal - + Ground sampling distance Tamaño de píxel - + Scale Escala - + Flying height Altura de vuelo - + Mean ground height Altura media en tierra - + View type Tipo de vista - + Northing Norte - + Easting Este - + EPSG code Código EPSG - + Omega Omega - + Phi Phi - + Kappa Kappa - + Photo in strip Fotograma dentro de pasada - + Spain España - + IGN topographic Topográfico IGN - + PNOA orthophoto Ortofoto PNOA - + Andorra Andorra - + Andorra topographic 1:25,000 1989 Andorra topográfico 1:25.000 1989 - + Andorra topographic 1:50,000 1987 Andorra topográfico 1:50.000 1987 - + Andorra orthophoto 1:5,000 2003 Andorra ortofoto 1:5.000 2003 - + Andorra Infrared orthophoto 1:5,000 2003 Andorra ortofoto infrarroja 1:5.000 2003 - + Andorra orthophoto 1:500-1,000 20cm 2008 Andorra ortofoto 1:500-1.000 20cm 2008 - + World Mundo - + NASA blue marble NASA blue marble - + Minimum download rect side not reached (%d px) Tamaño mínimo de descarga no alcanzado (%d px por lado) - + Maximum download area reached (%s px%s) Máxima área de descarga alcanzada (%s px%s) - + Area coordinates Coordenadas de área - + Enter west, north, east, south values in the project coordinates system or add the corresponding EPSG code in the following format: "429393.19 4580194.65 429493.19 4580294.65" or "429393.19 4580194.65 429493.19 4580294.65 EPSG:25831" or @@ -1075,22 +1075,22 @@ Do you want try open downloaded file in a external viewer? "EPSG:25831 429393.19 4580194.65 429493.19 4580294.65" - + Territorial topographic referential volume Referencial topográfico territorial volumen - + Selected layer polygons Polígonos seleccionados en una capa - + You must activate a vector layer with one or more selected polygons Es necesario activar una capa vectorial com uno o más polígonos seleccionados - + Data type: %s (%s) Polygon area: @@ -1109,62 +1109,57 @@ Carpeta de descargas: Nombre de archivo (%s): - + Your polygons have too many points: %d maximum %d Los polígonos tienen demasiados puntos: %d máximo %d - + Topographic map (topographical pyramid) Mapa topográfico (pirámide topográfica) - + Land cover map (temporal serie) Mapa de cubiertas del suelo (serie temporal) - + [TS] Land cover map [ST] Mapa de cubiertas del suelo - + Digital Terrain Model %s Modelo de elevaciones del terreno %s - + Incorrect coordinates format Formato de coordenadas incorrecto - + Instamaps pyramid Pirámide Instamaps - + Cadastral registry Catastro - + Geological map 1:25,000 (GT I) Mapa geológico 1:25.000 (GT I) - + Report photo bug Reportar error de fotograma - - Problem description: - Descripción del problema: - - - + Thanks for reporting an error in photogram: %s @@ -1175,7 +1170,7 @@ We try to fix it as soon as possible Intentaremos corregirlo lo antes posible - + Before reporting an error, bear in mind that the position of photograms is an approximation i will never completely fit the underlying cartography, since no terrain model has been used to project the imatge against. Furthermore, changes in instrumenation over time (wheter GPS is used or not, scanning and photogrammetric workflow) account for a very limited precision in positioning. Only large displacements in position (for example, an element that should appear near the center does not appear) or if there is an error in rotation (eg. the sea appears in the northern part of a photo). @@ -1188,156 +1183,241 @@ Solamente deben considerarse errores de ubicación si el fotograma está muy des ¿Quieres continuar? - + You must select one photogram Se debe seleccionar un fotograma + + + Keep scale + Mantener escala + + + + Anaglyph + Anaglifo + + + + Inverted stereo + Estéreo invertido + + + + Analog + Analógico + + + + Centered anaglyph photogram + Fotograma anaglifo central + + + + [AS] Centered anaglyph phootogram + [SA] Fotograma anaglifo central + + + + Centered rectified photogram (annual serie) + Fotograma rectificado central (serie anual) + + + + [AS] Centered rectified photogram + [SA] Fotograma rectificado central + + + + Centered photogram (annual serie) + Fotograma central (serie anual) + + + + [AS] Centered photogram + [SA] Fotograma central + + + + Centered anaglyph photogram %s (annual serie) + Fotograma anaglifo central %s (serie anual) + + + + This layer renders only the most centered photogram in the map view, you can zoom in for continuous navigation. Please note that current year may not have full photogram coverage + Muestra solo el fotograma más centrado en la vista mapa, puedes acercarte para obtener una navegació contínua. El año actual puede no tener una cobertura completa + + + + Photo: %s +Flight code: %s +Date: %s +Resolution: %.2fm + +Problem description: + Foto: %s +Código de vuelo: %s +Fecha: %s +Resolución: %.2fm + +Descripción del problema: + + + + Search photograms by name + Buscar fotogramas por nombre + + + + Photogram name: + Nombre de fotograma: + PhotoSearchSelectionDialog - + Years range Rango de años - + Resolution Resolución - + All Todas - + Very high (< 15 cm/px) Muy alta (<15 cm/px) - + High (approx. 25 cm/px) Alta (aprox. 25 cm/px) - + Medium (approx. 50 cm/px) Media (aprox. 50 cm/px) - + Low (> 60 cm/px) Baja (> 50 cm/px) - + Photogram Fotograma - + Date Fecha - + m/px m/px - + Information Información - + Year: %s Año: %s - + Photograms: %s Fotogramas: %s - + Download Descargar - + Request certificate Solicitar certificado - + Report photo bug Reportar error en fotograma - + View Visualizar - + Request certificate Solicitar certificado - + Request scan Solicitar escaneo - + Request scan Solicitar escaneo - + Adjust brightness Ajustar brillo - + Adjust brightness Ajustar brillo - + Unavailable or lost No disponible o perdido - + No publishable No publicable - + Scan required Escaneo requerido - + Available Disponible - + Note: Photograms locations are approximate Nota: La ubicación de los fotogramas es aproximada - + When photograms list is focused you can use up and down cursor keys to select current photo, left and right keys to select current year and @@ -1347,5 +1427,35 @@ las teclas de cursor arriba y abajo para seleccionar la foto activa, las teclas izquierda y derecha para seleccionar el año activo y la tecla intro para visualizar la foto + + + Rectified photogram "on the fly" + Fotograma rectificado "al vuelo" + + + + Anaglyph photogram "on the fly" + Fotograma anaglifo "al vuelo" + + + + View type + Tipo de vista + + + + Parallax: %+d%% + + + + + Inverted stereo + Estéreo invertido + + + + Photogram nominal orientation + Fotograma orientación nominal + diff --git a/images/search_name.pdn b/images/search_name.pdn new file mode 100644 index 0000000..22e7ffb Binary files /dev/null and b/images/search_name.pdn differ diff --git a/images/search_name.png b/images/search_name.png new file mode 100644 index 0000000..26ce46b Binary files /dev/null and b/images/search_name.png differ diff --git a/metadata.txt b/metadata.txt index f7d7d0f..96072d5 100644 --- a/metadata.txt +++ b/metadata.txt @@ -11,15 +11,15 @@ description=ICGC Open data access description_ca=Accés a dades obertes ICGC description_es=Acceso a datos abiertos ICGC about=Plugin for accessing open data published by the Cartographic and Geological Institute of Catalonia (Catalan mapping agency). - Includes spatial toponymic searches, streets, roads, coordinates in different reference systems, load of base data layers and download different vectorial and raster products. + Includes spatial toponymic searches, streets, roads, coordinates in different reference systems, acces to historical photo library and load of base data layers and download different vectorial and raster products. This plugin uses suds-py3, wsse libraries and land registry geo services. --- Plugin per accedir a dades obertes de l'Institut Cartogràfic i Geològic de Catalunya. - Inclou cerques espacials de topònims, carrers, carreteres, coordenades en diferents sistemes de referència, càrrega de dades de capes base i descàrrega de diferents productes vectorials i ràster. + Inclou cerques espacials de topònims, carrers, carreteres, coordenades en diferents sistemes de referència, càrrega de dades de capes base, accés a la fototeca històrica i descàrrega de diferents productes vectorials i ràster. Aquest plugin utilitza les llibreries suds-py3, wsse i serveis web del cadastre. --- Plugin para acceder a datos abiertos del Instituto Cartográfico y Geológico de Cataluña. - Incluye búsquedas espaciales de topónimos, calles, carreteras, coordenadas en diferentes sistemas de referencia, carga datos de capas base y descarga de diferentes productos vectoriales y raster. + Incluye búsquedas espaciales de topónimos, calles, carreteras, coordenadas en diferentes sistemas de referencia, carga datos de capas base, acceso a la fototeca histórica y descarga de diferentes productos vectoriales y raster. Este plugin utiliza las llibrerías suds-py3, wsse y servicios web del catastro. tags=ICGC,Catalunya,Cataluña,Catalonia,find,search,site,place,street,road,WMS icon=icon.png @@ -28,8 +28,14 @@ email=qgis.openicgc@icgc.cat qgisMinimumVersion=2.99 qgisMaximumVersion=3.99 -version=1.1.0 -changelog=v1.1.0 (2022-02-14) +version=1.1.1 +changelog=v1.1.1 (2022-04-19) + - Added photo library rectification "on the fly" + - Added photo library stereo anaglyph generation "on the fly" + - Added anaglyph central photo layer + - Improved point and rectangle searches + + v1.1.0 (2022-02-14) - Added access to ICGC historical photo library (visualization and downloads) - Added download geological map GT I and GT VI product - Fixed timeline bars to skip one year when click on it diff --git a/openicgc.py b/openicgc.py index af24b4e..a2eba4f 100644 --- a/openicgc.py +++ b/openicgc.py @@ -17,10 +17,10 @@ ******************************************************************************* """ -# Add a additional library folder to pythonpath +# Add a additional library folder to pythonpath (for external libraries) import os import sys -sys.path.append(os.path.join(os.path.dirname(__file__), "lib")) # Per la suds que ha de ser global... +sys.path.append(os.path.join(os.path.dirname(__file__), "lib")) # Import base libraries import re @@ -45,6 +45,7 @@ # Initialize Qt resources from file resources_rc.py from . import resources_rc +# Detect import relative mode (for release) or global import mode (for debug) is_import_relative = os.path.exists(os.path.join(os.path.dirname(__file__), "qlib3")) if is_import_relative: # Import basic plugin functionalities @@ -94,7 +95,11 @@ set_html_font_size = lambda text, size=9: ('%s' % (size, text.replace("\n", "
").replace(" ", " "))) # Constants -PHOTOLIB_WFS = "https://fototeca-connector.icgc.cat/" #"http://sedockersec01.icgc.local:80" #"http://seuatdlinux01:5000" "http://localhost:5000" +PHOTOLIB_WFS_MAX_FEATURES = 1000 +PHOTOLIB_WFS = "https://fototeca-connector.icgc.cat/" +#PHOTOLIB_WFS = "http://sedockersec01.icgc.local/" +#PHOTOLIB_WFS = "http://seuatdlinux01.icgc.local/" +#PHOTOLIB_WFS = "http://localhost:5000/" PHOTOLIB_WMS = PHOTOLIB_WFS @@ -398,7 +403,8 @@ def __init__(self, iface): # We created a GeoFinder object that will allow us to perform spatial searches self.geofinder = GeoFinder() self.geofinder_dialog = GeoFinderDialog(self.geofinder, title=self.tr("Spatial search"), - columns_list=[self.tr("Name"), self.tr("Type"), self.tr("Municipality"), self.tr("Region")]) + columns_list=[self.tr("Name"), self.tr("Type"), self.tr("Municipality"), self.tr("Region")], + keep_scale_text=self.tr("Keep scale")) # Initialize reference to PhotoSearchSelectionDialog self.photo_search_dialog = None @@ -448,6 +454,9 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): self.combobox.setFixedSize(QSize(250,24)) self.combobox.setEditable(True) self.combobox.setToolTip(self.TOOLTIP_HELP) + self.combobox.addItems(self.get_setting_value("last_searches", [])) + self.combobox.setCurrentText("") + self.combobox.setMaxVisibleItems(20) self.combobox.activated.connect(self.run) # Press intro and select combo value # Gets available Topo5k files to simulate WMS-T service @@ -480,7 +489,12 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): ortoxpres_color_list = [(str(year), layer_id, layer_name) for layer_id, layer_name, ortho_type, color, year in historic_ortho_list if ortho_type == "ortoxpres" and color != "irc"] ortoxpres_color_year, ortoxpres_color_layer_id, ortoxpres_color_layer_name = ortoxpres_color_list[-1] if ortoxpres_color_list else (None, None, None) ortoxpres_infrared_list = [(str(year), layer_id, layer_name) for layer_id, layer_name, ortho_type, color, year in historic_ortho_list if ortho_type == "ortoxpres" and color == "irc"] - ortoxpres_infrared_year, ortoxpres_infrared_layer_id, ortoxpres_infrared_layer_name = ortoxpres_infrared_list[-1] if ortoxpres_infrared_list else (None, None, None) + ortoxpres_infrared_year, ortoxpres_infrared_layer_id, ortoxpres_infrared_layer_name = ortoxpres_infrared_list[-1] if ortoxpres_infrared_list else (None, None, None) + + # Gets anaglyph fotograms. Last year can not have full photograms coverage, we select previous year as default + photolib_wms_url = PHOTOLIB_WMS + photolib_time_series_list, photolib_current_time = self.layers.get_wms_t_time_series(photolib_wms_url, "anaglif_central") + photolib_current_time = str(int(photolib_current_time) - 1) if photolib_current_time else photolib_current_time # Gets available download source data fme_services_list = get_services() @@ -497,8 +511,7 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): # Add new toolbar with plugin options (using pluginbase functions) style = self.iface.mainWindow().style() - self.toolbar = self.gui.configure_toolbar(self.tr("Open ICGC Toolbar") + (" lite" if self.lite else ""), - [ + self.toolbar = self.gui.configure_toolbar(self.tr("Open ICGC Toolbar") + (" lite" if self.lite else ""), [ self.tr("Find"), # Label text self.combobox, # Editable combobox (self.tr("Find place names and adresses"), self.run, QIcon(":/lib/qlib3/geofinderdialog/images/geofinder.png")), # Action button @@ -511,7 +524,7 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): QIcon(":/lib/qlib3/base/images/cat_topo250k.png")), (self.tr("Territorial topographic referential"), None, QIcon(":/lib/qlib3/base/images/cat_topo5k.png"), enable_http_files, [ (self.tr("Territorial topographic referential %s (temporal serie)") % topo5k_year, - lambda _checked, topo5k_year=topo5k_year:self.add_wms_t_layer(self.tr("[TS] Territorial topographic referential"), None, topo5k_year, "default", "image/jpeg", topo5k_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, resampling_bilinear=True, set_current=True), + lambda _checked, topo5k_year=topo5k_year:self.add_wms_t_layer(self.tr("[TS] Territorial topographic referential"), None, topo5k_year, None, "default", "image/jpeg", topo5k_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, resampling_bilinear=True, set_current=True), QIcon(":/lib/qlib3/base/images/cat_topo5k.png")) for topo5k_year, _url in topo5k_time_series_list]), (self.tr("Topographic map 1:50,000"), @@ -549,7 +562,7 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): lambda _checked:self.layers.add_wms_layer(self.tr("Geological map 1:250,000"), "https://geoserveis.icgc.cat/mgc250mv2(raster)/wms/service", ["0"], ["default"], "image/png", 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_geo250k.png")), (self.tr("Land cover map (temporal serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[TS] Land cover map"), "https://geoserveis.icgc.cat/servei/catalunya/cobertes-sol/wms", "serie_temporal", "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[TS] Land cover map"), "https://geoserveis.icgc.cat/servei/catalunya/cobertes-sol/wms", "serie_temporal", None, "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_landcover.png")), "---", ] + [(self.tr("Digital Terrain Model %s") % dtm_name, @@ -559,10 +572,10 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): ) for dtm_name, dtm_url in dtm_list] + [ "---", (self.tr("NDVI color (temporal serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[TS] NDVI color"), "https://geoserveis.icgc.cat/servei/catalunya/ndvi/wms", "ndvi_serie_anual_color", "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[TS] NDVI color"), "https://geoserveis.icgc.cat/servei/catalunya/ndvi/wms", "ndvi_serie_anual_color", None, "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_landcover.png")), (self.tr("NDVI (temporal serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[TS] NDVI"), None, ndvi_current_time, "default", "image/jpeg", ndvi_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[TS] NDVI"), None, ndvi_current_time, None, "default", "image/jpeg", ndvi_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_shadows.png"), enable_http_files), "---", (self.tr("Color orthophoto"), None, QIcon(":/lib/qlib3/base/images/cat_ortho5k.png"), [ @@ -577,16 +590,16 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): "---", ] + [ (self.tr("Color orthophoto %s (temporal serie)") % ortho_year, - lambda _checked,layer_id=layer_id:self.add_wms_t_layer(self.tr("[TS] Color orthophoto"), ortho_wms_url, layer_id, "default", "image/jpeg", ortho_color_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked,layer_id=layer_id:self.add_wms_t_layer(self.tr("[TS] Color orthophoto"), ortho_wms_url, layer_id, None, "default", "image/jpeg", ortho_color_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5k.png")) for ortho_year, layer_id in reversed(ortho_color_time_series_list) ] + [ "---", (self.tr("Color orthophoto (annual serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[AS] Color orthophoto"), "https://geoserveis.icgc.cat/servei/catalunya/orto-territorial/wms", "ortofoto_color_serie_anual", "", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[AS] Color orthophoto"), "https://geoserveis.icgc.cat/servei/catalunya/orto-territorial/wms", "ortofoto_color_serie_anual", None, "", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5kbw.png")), ]), (self.tr("Satellite color orthophoto (monthly serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[MS] Satellite color orthophoto"), "https://geoserveis.icgc.cat/icgc_sentinel2/wms/service", "sen2rgb", "", "image/jpeg", None, 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[MS] Satellite color orthophoto"), "https://geoserveis.icgc.cat/icgc_sentinel2/wms/service", "sen2rgb", None, "", "image/jpeg", None, 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5kbw.png")), "---", (self.tr("Infrared orthophoto"), None, QIcon(":/lib/qlib3/base/images/cat_ortho5ki.png"), [ @@ -601,17 +614,31 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): "---" ] + [ (self.tr("Infrared orthophoto %s (temporal serie)") % ortho_year, - lambda _checked,layer_id=layer_id:self.add_wms_t_layer(self.tr("[TS] Infrared orthophoto"), ortho_wms_url, layer_id, "default", "image/jpeg", ortho_infrared_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked,layer_id=layer_id:self.add_wms_t_layer(self.tr("[TS] Infrared orthophoto"), ortho_wms_url, layer_id, None, "default", "image/jpeg", ortho_infrared_time_series_list, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5k.png")) for ortho_year, layer_id in reversed(ortho_infrared_time_series_list) ] + [ "---", (self.tr("Infrared orthophoto (annual serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[AS] Infrared orthophoto"), "https://geoserveis.icgc.cat/servei/catalunya/orto-territorial/wms", "ortofoto_infraroig_serie_anual", "", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[AS] Infrared orthophoto"), "https://geoserveis.icgc.cat/servei/catalunya/orto-territorial/wms", "ortofoto_infraroig_serie_anual", None, "", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5kbw.png")), ]), (self.tr("Satellite infrared orthophoto (monthly serie)"), - lambda _checked:self.add_wms_t_layer(self.tr("[MS] Satellite infared orthophoto"), "https://geoserveis.icgc.cat/icgc_sentinel2/wms/service", "sen2irc", "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), + lambda _checked:self.add_wms_t_layer(self.tr("[MS] Satellite infared orthophoto"), "https://geoserveis.icgc.cat/icgc_sentinel2/wms/service", "sen2irc", None, "default", "image/jpeg", None, 25831, "referer=ICGC&bgcolor=0x000000", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=True), QIcon(":/lib/qlib3/base/images/cat_ortho5ki.png")), + "---", + (self.tr("Centered anaglyph photogram"), None, QIcon(":/lib/qlib3/photosearchselectiondialog/images/stereo_preview.png"), [ + (self.tr("Centered anaglyph photogram %s (annual serie)") % anaglyph_year, + lambda _checked,anaglyph_year=anaglyph_year,anaglyph_layer=anaglyph_layer:self.add_wms_t_layer(self.tr("[AS] Centered anaglyph phootogram"), photolib_wms_url, anaglyph_layer, str(anaglyph_year), "central,100,false", "image/png", None, 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=False), + QIcon(":/lib/qlib3/photosearchselectiondialog/images/stereo_preview.png")) for anaglyph_year, anaglyph_layer in reversed(photolib_time_series_list) + ]) + ] + ([ + (self.tr("Centered rectified photogram (annual serie)"), + lambda _checked:self.add_wms_t_layer(self.tr("[AS] Centered rectified photogram"), photolib_wms_url, "ortoxpres_central", photolib_current_time, "central", "image/png", None, 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=False), + QIcon(":/lib/qlib3/photosearchselectiondialog/images/rectified_preview.png")), + (self.tr("Centered photogram (annual serie)"), + lambda _checked:self.add_wms_t_layer(self.tr("[AS] Centered photogram"), photolib_wms_url, "foto_central", photolib_current_time, "central", "image/png", None, 25831, "referer=ICGC", self.backgroup_map_group_name, only_one_map_on_group=False, set_current=False), + QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_preview.png")), + ] if self.debug_mode else []) + [ "---" ] + ([ (self.tr("Instamaps pyramid"), @@ -655,7 +682,7 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): QIcon(":/lib/qlib3/base/images/world.png")), ]), "---", - ] if self.extra_countries else []) + [ + ] if self.extra_countries or self.debug_mode else []) + [ (self.tr("Delete background maps"), lambda _checked:self.legend.empty_group_by_name(self.backgroup_map_group_name), QIcon(":/lib/qlib3/base/images/wms_remove.png"), True, False, "delete_background") ]), @@ -666,7 +693,8 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): ] + ([ (self.tr("Search photograms"), (self.enable_search_photos, self.pair_photo_search_checks), QIcon(":/plugins/openicgc/images/search.png"), True, True, "photo_search", [ (self.tr("Search photograms interactively"), (self.enable_search_photos, self.pair_photo_search_checks), QIcon(":/plugins/openicgc/images/search.png"), True, True, "photo_search_2"), - (self.tr("Search photograms by coordinates"), lambda _checked:self.search_photos(), QIcon(":/plugins/openicgc/images/search_coord.png"), True, False), + (self.tr("Search photograms by coordinates"), lambda _checked:self.search_photos_by_point(), QIcon(":/plugins/openicgc/images/search_coord.png"), True, False), + (self.tr("Search photograms by name"), lambda _checked:self.search_photos_by_name(), QIcon(":/plugins/openicgc/images/search_name.png"), True, False), ]), (self.tr("Download tool"), self.disable_download_global_check, QIcon(":/plugins/openicgc/images/download_area.png"), True, True, "download", download_vector_submenu + ["---"] + download_raster_submenu + [ @@ -682,6 +710,9 @@ def initGui(self, check_qgis_updates=True, check_icgc_updates=False): (self.tr("Desaturate raster layer"), lambda _checked:self.layers.set_saturation(self.iface.mapCanvas().currentLayer(), -100, True) if type(self.iface.mapCanvas().currentLayer()) is QgsRasterLayer else None, QIcon(":/lib/qlib3/base/images/desaturate.png")), + (self.tr("Anaglyph"), + lambda _checked:self.tools.show_anaglyph_dialog(self.iface.mapCanvas().currentLayer(), self.tr("Anaglyph"), self.tr("Anaglyph"), self.tr("Inverted stereo")), + QIcon(":/lib/qlib3/photosearchselectiondialog/images/stereo_preview.png")), (self.tr("Shading DTM layer"), self.shading_dtm, QIcon(":/lib/qlib3/base/images/cat_shadows.png")), @@ -872,11 +903,14 @@ def pair_photo_search_checks(self, status): def run(self, checked): # I add checked param, because the mapping of the signal triggered passes a parameter """ Basic plugin call, which reads the text of the combobox and the search for the different web services available """ self.find(self.combobox.currentText()) + # Save last searches in persistent app settings + searches_list = [self.combobox.itemText(i) for i in range(self.combobox.count())][-self.combobox.maxVisibleItems():] + self.set_setting_value("last_searches", searches_list) - def add_wms_t_layer(self, layer_name, url, layer_id, style, image_format, time_series_list=None, epsg=None, extra_tags="", group_name="", group_pos=None, only_one_map_on_group=False, collapsed=True, visible=True, transparency=None, saturation=None, resampling_bilinear=False, resampling_cubic=False, set_current=False): + def add_wms_t_layer(self, layer_name, url, layer_id, time, style, image_format, time_series_list=None, epsg=None, extra_tags="", group_name="", group_pos=None, only_one_map_on_group=False, collapsed=True, visible=True, transparency=None, saturation=None, resampling_bilinear=False, resampling_cubic=False, set_current=False): """ Add WMS-T layer and enable timeseries dialog """ # Add WMS-T - layer = self.layers.add_wms_t_layer(layer_name, url, layer_id, style, image_format, time_series_list, epsg, extra_tags, group_name, group_pos, only_one_map_on_group, collapsed, visible, transparency, saturation, resampling_bilinear, resampling_cubic, set_current) + layer = self.layers.add_wms_t_layer(layer_name, url, layer_id, time, style, image_format, time_series_list, epsg, extra_tags, group_name, group_pos, only_one_map_on_group, collapsed, visible, transparency, saturation, resampling_bilinear, resampling_cubic, set_current) if layer: if type(layer) in [QgsRasterLayer, QgsVectorLayer]: # Show timeseries dialog @@ -885,6 +919,14 @@ def add_wms_t_layer(self, layer_name, url, layer_id, style, image_format, time_s if self.time_series_action: self.time_series_action.setEnabled(True) self.time_series_action.setChecked(self.tools.time_series_dialog is not None and self.tools.time_series_dialog.isVisible()) + # Show stereo anaglyph options + if layer_id.lower().startswith("anaglif"): + self.tools.show_anaglyph_dialog(layer, self.tr("Anaglyph"), self.tr("Anaglyph"), self.tr("Inverted stereo")) + # Show "on the fly" central photogram rendering layers warning + if layer_id.lower().endswith("_central"): + message = self.tr("This layer renders only the most centered photogram in the map view, you can zoom in for continuous navigation. Please note that current year may not have full photogram coverage") + self.iface.messageBar().pushMessage(layer_name, message, level=Qgis.Info, duration=10) + return layer def find(self, user_text): @@ -907,8 +949,6 @@ def find(self, user_text): west, north, east, south, epsg = self.geofinder_dialog.get_rectangle() # We resituate the map (implemented in parent PluginBase) self.set_map_rectangle(west, north, east, south, epsg) - if self.debug_mode: - print("") else: # We get point coordinates x, y, epsg = self.geofinder_dialog.get_point() @@ -917,11 +957,12 @@ def find(self, user_text): QMessageBox.warning(self.iface.mainWindow(), self.tr("Spatial search"), self.tr("Error, location without coordinates")) return + scale = self.geofinder_dialog.get_scale() # We resituate the map (implemented in parent PluginBase) - self.set_map_point(x, y, epsg) - if self.debug_mode: - print("") - + self.set_map_point(x, y, epsg, scale) + + if self.debug_mode: + print("") def is_unsupported_file(self, pathname): return self.is_file_type(pathname, ["dgn", "dwg"]) @@ -1386,10 +1427,6 @@ def get_menu_names(self, action_name, exclude_list): names_list.append(subaction.text()) return names_list - def check_qgis_version(self, version=31004): - """ Checks QGIS old versions with plugin problems """ - return Qgis.QGIS_VERSION_INT >= version - def show_qgis_version_warnings(self): """ Show QGIS old versions warnigs """ LogInfoDialog( @@ -1573,29 +1610,45 @@ def enable_search_photos(self, checked=False): self.gui.enable_tool(self.tool_photo_search) self.iface.messageBar().pushMessage(self.tr("Photograms search tool"), self.tr("Select a point"), level=Qgis.Info, duration=5) - def search_photos(self, x=None, y=None, photolib_wfs=PHOTOLIB_WFS, date_field="flight_date"): - """ Search photos in photo library by selected point """ + def search_photos_by_point(self): + """ Search photos in photo library by text point coordinates """ + # Ask coordinates title = self.tr("Search photograms") - epsg = None - - # If no coordinate available, we request it + msg_text = self.tr('Enter an x y value in the project coordinate system or add the corresponding EPSG code in the following format:\n "429393.19 4580194.65" or "429393.19 4580194.65 EPSG:25831" or "EPSG:25831 429393.19 4580194.65"') + coord_text, ok_pressed = QInputDialog.getText(self.iface.mainWindow(), title, + set_html_font_size(msg_text), QLineEdit.Normal, "") + if not ok_pressed: + return + # Use GeoFinder static function to parse coordinate text + x, y, epsg = GeoFinder.get_point_coordinate(coord_text) if not x or not y: - msg_text = self.tr('Enter an x y value in the project coordinate system or add the corresponding EPSG code in the following format:\n "429393.19 4580194.65" or "429393.19 4580194.65 EPSG:25831" or "EPSG:25831 429393.19 4580194.65"') - coord_text, ok_pressed = QInputDialog.getText(self.iface.mainWindow(), title, - set_html_font_size(msg_text), QLineEdit.Normal, "") - if not ok_pressed: - return - # Use GeoFinder static function to parse coordinate text - x, y, epsg = GeoFinder.get_point_coordinate(coord_text) - if not x or not y: - QMessageBox.warning(self.iface.mainWindow(), title, "Incorrect coordinate format") - return + QMessageBox.warning(self.iface.mainWindow(), title, "Incorrect coordinate format") + return + # Search photo coordinates + self.search_photos(x, y) + + def search_photos_by_name(self): + """ Search photos in photo library by photo name """ + # Ask photo name + title = self.tr("Search photograms") + msg_text = self.tr('Photogram name:') + " " * 50 + photo_name, ok_pressed = QInputDialog.getText(self.iface.mainWindow(), title, + set_html_font_size(msg_text), QLineEdit.Normal, "") + if not ok_pressed or not photo_name: + return + # Search photo name + self.search_photos(name=photo_name.strip()) + + def search_photos(self, x=None, y=None, name=None, photolib_wfs=PHOTOLIB_WFS, date_field="flight_date"): + """ Search photos in photo library by selected point or photo name """ + title = self.photo_search_label.replace(": %s", "") + epsg = None # Check existence of old photo search group_pos = 0 group = self.legend.get_group_by_name(self.photos_group_name) if group and len(self.layers.get_group_layers(group)) > 0: - if QMessageBox.question(self.iface.mainWindow(), self.photo_search_label.replace(": %s", ""), + if QMessageBox.question(self.iface.mainWindow(), title, self.tr('It exists a previous photo search. Do you want close it?'), QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return False self.legend.empty_group(group) @@ -1603,39 +1656,54 @@ def search_photos(self, x=None, y=None, photolib_wfs=PHOTOLIB_WFS, date_field="f if not group: # If not exists download group return -1 group_pos = self.legend.get_group_position_by_name(self.download_group_name) + 1 + + # Fix event problems betwen photo layer and photo dialog for QGIS versions < 3.10 + # Needs create photo dialog previous to photo layer... + if not self.photo_search_dialog and not self.check_qgis_version(310000): + self.show_photo_search_dialog(None, []) + self.photo_search_dialog.hide() - with WaitCursor(): - if not epsg: - epsg = int(self.project.get_epsg()) - # Transform point coordinates to EPSG 4326 - point = QgsPointXY(x, y) - if epsg != 4326: - transformation = QgsCoordinateTransform( - QgsCoordinateReferenceSystem("EPSG:%s" % epsg), - QgsCoordinateReferenceSystem("EPSG:4326"), - QgsProject.instance()) - point = transformation.transform(point) + if self.debug_mode: + print("Search photo: %s" % photolib_wfs) - # Get municipality information of coordinate - found_dict_list = self.find_point_secure(point.y(), point.x(), 4326) # En geogràfiques el topofinder vol lat, lon (y, x) - municipality = found_dict_list[0]['nomMunicipi'] if found_dict_list else "" - if municipality: - layer_name = self.photo_search_label % municipality - else: - if x >= 100 and y >= 100: - layer_name = self.photo_search_label % self.tr("Coord %s %s") % ("%.2f" % x,"%.2f" % y) + with WaitCursor(): + photo_layer = None + + # Search by coordinates + if x and y: + if not epsg: + epsg = int(self.project.get_epsg()) + + # Get municipality information of coordinate + found_dict_list = self.find_point_secure(x, y, epsg) + municipality = found_dict_list[0]['nomMunicipi'] if found_dict_list else "" + if municipality: + layer_name = self.photo_search_label % municipality else: - layer_name = self.photo_search_label % self.tr("Coord %s %s") % (x, y) + if x >= 100 and y >= 100: + layer_name = self.photo_search_label % self.tr("Coord %s %s") % ("%.2f" % x,"%.2f" % y) + else: + layer_name = self.photo_search_label % self.tr("Coord %s %s") % (x, y) + + # Search point in photo library (EPSG 4326) + x, y = self.crs.transform_point(x, y, epsg, 4326) + photo_layer = self.layers.add_wfs_layer(layer_name, photolib_wfs, + ["icgc:fotogrames"], 4326, + filter="SELECT * FROM fotogrames WHERE ST_Intersects(msGeometry, ST_GeometryFromText('POINT(%f %f)'))" % (x, y), + extra_tags="referer=ICGC", + group_name=self.photos_group_name, group_pos=group_pos, only_one_map_on_group=False, only_one_visible_map_on_group=True, + collapsed=False, visible=True, transparency=None, set_current=True) + + # Search by name + if name and len(name) > 7: # at least flight code... + layer_name = self.photo_search_label % name + photo_layer = self.layers.add_wfs_layer(layer_name, photolib_wfs, + ["icgc:fotogrames"], 4326, + filter="SELECT * FROM fotogrames WHERE name LIKE '%s'" % (name), + extra_tags="referer=ICGC", + group_name=self.photos_group_name, group_pos=group_pos, only_one_map_on_group=False, only_one_visible_map_on_group=True, + collapsed=False, visible=True, transparency=None, set_current=True) - # Search point in photo library - if self.debug_mode: - print("Search photo: %s" % photolib_wfs) - photo_layer = self.layers.add_wfs_layer(layer_name, photolib_wfs, - ["icgc:fotogrames"], 4326, - filter="SELECT * FROM fotogrames WHERE ST_Intersects(msGeometry, ST_GeometryFromText('POINT(%f %f)'))" % (point.x(), point.y()), - extra_tags="referer=ICGC", - group_name=self.photos_group_name, group_pos=group_pos, only_one_map_on_group=False, only_one_visible_map_on_group=True, - collapsed=False, visible=True, transparency=None, set_current=True) if not photo_layer: return # Translate field names @@ -1665,6 +1733,7 @@ def search_photos(self, x=None, y=None, photolib_wfs=PHOTOLIB_WFS, date_field="f "omega": self.tr("Omega"), "phi": self.tr("Phi"), "kappa": self.tr("Kappa"), + "analog": self.tr("Analog"), }) # Get years of found photograms self.search_photos_year_list = sorted(list(set([(f[date_field].date().year() if type(f[date_field]) == QDateTime \ @@ -1677,6 +1746,7 @@ def search_photos(self, x=None, y=None, photolib_wfs=PHOTOLIB_WFS, date_field="f self.layers.set_categories_visible(photo_layer, self.search_photos_year_list[1:], False) self.layers.enable_feature_count(photo_layer) self.layers.zoom_to_full_extent(photo_layer) + self.layers.set_visible(photo_layer, False) # Show photo search dialog self.search_photos_year_list.reverse() @@ -1684,30 +1754,56 @@ def search_photos(self, x=None, y=None, photolib_wfs=PHOTOLIB_WFS, date_field="f # Map change selection feature event photo_layer.selectionChanged.connect(self.on_change_photo_selection) - photo_layer.willBeDeleted.connect(self.photo_search_dialog.reset) + if self.photo_search_dialog: + photo_layer.willBeDeleted.connect(self.photo_search_dialog.reset) + + # Disable search tool + self.gui.enable_tool(None) - # Disable search tool - self.gui.enable_tool(None) + ## Show warning if max results + #if photo_layer and photo_layer.featureCount() == PHOTOLIB_WFS_MAX_FEATURES: + # QMessageBox.warning(self.iface.mainWindow(), title, + # self.tr("The maximum number of results (%d) has been reached.\nThe query may have more results than are displayed.") % PHOTOLIB_WFS_MAX_FEATURES) - def photo_preview(self, photo_name, only_one=True, photolib_wms=PHOTOLIB_WMS): + def photo_preview(self, photo_name, rectified=False, stereo=False, only_one=True, photolib_wms=PHOTOLIB_WMS): """ Load photogram raster layer """ if only_one: - # Remove previous preview layers - self.layers.remove_layer_by_id(self.photo_layer_id) + # Get previous photo_layer to update or create it + photo_layer = self.layers.get_by_id(self.photo_layer_id) else: + photo_layer = None # Disable previous preview layers - self.legend.set_group_items_visible_by_name(self.photo_group_name, False) + self.legend.set_group_items_visible_by_name(self.photos_group_name, False) self.layers.set_visible_by_id(self.photo_search_layer_id, True) + # Determine WMS layer to load + layer_name = "anaglif" if stereo else "ortoxpres" if rectified else "fotos" + if stereo: + photo_style = ",".join([photo_name, \ + str(self.photo_search_dialog.get_parallax()), \ + ("true" if self.photo_search_dialog.is_inverted_stereo() else "false") \ + ]) + else: + photo_style = photo_name + # We don't want change current selected layer current_layer = self.layers.get_current_layer() - # Load new preview layer at top (using WMS or UNC path to file) + # Show debug info if self.debug_mode: - print("Show photo: %s / %s" % (photolib_wms, photo_name)) - photo_layer = self.layers.add_wms_layer(self.photo_label % photo_name, photolib_wms, - ["fotos"], [photo_name], "image/png", self.project.get_epsg(), extra_tags="referer=ICGC&bgcolor=0x000000", - group_name=self.photos_group_name, group_pos=0, only_one_map_on_group=False, only_one_visible_map_on_group=False, - collapsed=False, visible=True, transparency=None, set_current=False) + print("Show photo: %s %s" % (photolib_wms, photo_style)) + photo_label = self.photo_label % photo_name + if photo_layer: + # Update current photo_layer + self.layers.update_wms_layer(photo_layer, wms_layer=layer_name, wms_style=photo_style) + photo_layer.setName(photo_label) + self.layers.set_visible(photo_layer) + self.legend.set_group_visible_by_name(self.photos_group_name) + else: + # Load new preview layer at top (using WMS or UNC path to file) + photo_layer = self.layers.add_wms_layer(photo_label, photolib_wms, + [layer_name], [photo_style], "image/png", self.project.get_epsg(), extra_tags="referer=ICGC&bgcolor=0x000000", + group_name=self.photos_group_name, group_pos=0, only_one_map_on_group=False, only_one_visible_map_on_group=False, + collapsed=False, visible=True, transparency=None, set_current=False) # Restore previous selected layer if current_layer: self.layers.set_current_layer(current_layer) @@ -1726,6 +1822,8 @@ def show_photo_search_dialog(self, layer, years_list, current_year=None, title=N update_photo_selection_callback = lambda photo_id: self.layers.set_selection(layer, [photo_id] if photo_id else []) show_info_callback = lambda photo_id: self.iface.openFeatureForm(layer, layer.getFeature(photo_id)) preview_callback = lambda photo_id: self.photo_preview(layer.getFeature(photo_id)['name']) + rectified_preview_callback = lambda photo_id: self.photo_preview(layer.getFeature(photo_id)['name'], rectified=True) + stereo_preview_callback = lambda photo_id: self.photo_preview(layer.getFeature(photo_id)['name'], stereo=True) download_callback = lambda photo_id: self.photo_download_action.trigger() request_certificate_callback = None #lambda photo_id: self.tools.send_email("qgis.openicgc@icgc.cat", #"OpenICGC QGIS plugin. certificate %s" % layer.getFeature(photo_id)['name'], @@ -1733,14 +1831,16 @@ def show_photo_search_dialog(self, layer, years_list, current_year=None, title=N request_scan_callback = None #lambda photo_id: self.tools.send_email("qgis.openicgc@icgc.cat", #"OpenICGC QGIS plugin. scan %s" % layer.getFeature(photo_id)['name'], #self.tr("Scan request for photogram: %s") % layer.getFeature(photo_id)['name']) - report_photo_bug_callback = lambda photo_id: self.report_photo_bug(layer.getFeature(photo_id)['name'], ) + report_photo_bug_callback = lambda photo_id: self.report_photo_bug(layer.getFeature(photo_id)['name'], layer.getFeature(photo_id)['flight_code'], layer.getFeature(photo_id)['flight_date'], layer.getFeature(photo_id)['gsd'] ) if not self.photo_search_dialog: self.photo_search_dialog = PhotoSearchSelectionDialog(layer, years_list, current_year, - update_photo_time_callback, update_photo_selection_callback, show_info_callback, preview_callback, + update_photo_time_callback, update_photo_selection_callback, show_info_callback, + preview_callback, rectified_preview_callback, stereo_preview_callback, None, download_callback, request_certificate_callback, request_scan_callback, report_photo_bug_callback, - parent=self.iface.mainWindow()) + autoshow=True, parent=self.iface.mainWindow()) # Align dialog to right + self.photo_search_dialog.hide() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.photo_search_dialog) # Map visibility event to refresh any control if necessary. This is implemented in # change layer event that's why i send a change layer signal @@ -1749,7 +1849,8 @@ def show_photo_search_dialog(self, layer, years_list, current_year=None, title=N # Configure search result information self.photo_search_dialog.set_info(layer, years_list, current_year, - update_photo_time_callback, update_photo_selection_callback, show_info_callback, preview_callback, None, + update_photo_time_callback, update_photo_selection_callback, show_info_callback, + preview_callback, rectified_preview_callback, stereo_preview_callback, None, download_callback, request_certificate_callback, request_scan_callback, report_photo_bug_callback) # Mostrem el diàleg self.photo_search_dialog.show() @@ -1764,8 +1865,11 @@ def update_photo_search_layer_year(self, photo_layer, current_year, range_year): if photo_layer: self.layers.set_categories_visible(photo_layer, set(self.search_photos_year_list) - set(year_range), False) self.layers.set_categories_visible(photo_layer, year_range, True) + self.layers.set_current_layer(photo_layer) # click in categories of layer can unselect layer... we fix it + self.layers.set_visible(photo_layer) # force visibility of photo layer + self.legend.set_group_visible_by_name(self.photos_group_name) # force visibility of photo group - def report_photo_bug(self, photo_name): + def report_photo_bug(self, photo_name, flight_code="", photo_date="", photo_resolution=0): """ Report a photo bug """ # description, ok_pressed = QInputDialog.getMultiLineText(self.iface.mainWindow(), self.tr("Report photo bug"), # set_html_font_size(self.tr("Looks like you found an error in photogram:\n%s\n\nWe will register the problem and try to fix it. Could you describe it briefly?") % photo_name)) @@ -1778,6 +1882,6 @@ def report_photo_bug(self, photo_name): return self.tools.send_email("qgis.openicgc@icgc.cat", "Error en el fotograma %s" % photo_name, # Static text no translated - self.tr("Problem description: ")) + self.tr("Photo: %s\nFlight code: %s\nDate: %s\nResolution: %.2fm\n\nProblem description: ") % (photo_name, flight_code, photo_date, photo_resolution or 0)) QMessageBox.information(self.iface.mainWindow(), title, self.tr("Thanks for reporting an error in photogram:\n%s\n\nWe try to fix it as soon as possible") % photo_name) diff --git a/qlib3/base/aboutdialog.py b/qlib3/base/aboutdialog.py index badfd63..6333e2f 100644 --- a/qlib3/base/aboutdialog.py +++ b/qlib3/base/aboutdialog.py @@ -1,102 +1,102 @@ -# -*- coding: utf-8 -*- -""" -******************************************************************************* -Mòdul amb classe diàleg per mostrar informació bàsica del plugin i logo el ICGC ---- -Module with a dialog class to display basic information of plugin and ICGC logo - - ------------------- - begin : 2019-01-18 - author : Albert Adell - email : albert.adell@icgc.cat -******************************************************************************* -""" - -import os -import sys - -from PyQt5 import uic -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPalette, QColor, QFontMetrics, QPixmap -from PyQt5.QtWidgets import QStyle, QDialogButtonBox, QDialog, QApplication - -ui_about, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_about.ui')) - - -class AboutDialog(QDialog, ui_about): - """ Classe diàleg per mostrar informació bàsica del plugin i logo el ICGC - --- - Class to display basic information of plugin and ICGC logo - """ - - def __init__(self, app_name, app_info, app_icon=None, app_pixmap=None, title="Sobre", autoshow=True, new_line=" ", parent=None): - """ Inicialització del diàleg "about", cal informar de: - - app_name: Títol del diàleg - - app_icon: Icona del diàleg - - app_info: Informació a mostrar - - title: Títol de la finestra - Opcionalment: - - autoshow: Mostra el diàleg automàticament al crear-lo - - new_line: Caràcters a substituir per un canvi de linia - - parent: Especifica la finestra pare del diàleg - --- - Initialization of the "about" dialog, you need to report: -             - app_name: Title of the dialog -             - app_icon: Icon of the dialog -             - app_info: Information to show -             - title: Window title -             Optionally: -             - autoshow: Show the dialog automatically when you create it -             - new_line: Characters to be replaced by a change of line -             - parent: Specifies the parent window of the dialog - """ - QDialog.__init__(self, parent) - self.setupUi(self) - self.ui = self # Per compatibilitat QGIS2/3 - - # Canviem el títol i la icona - if not title: - title = self.windowTitle() - self.setWindowTitle("%s %s" % (title, app_name)) - if app_icon and sys.platform == "win32": - self.setWindowIcon(app_icon) - - # Escalem la imatge de logo mantenint proporcions - self.label_banner.setScaledContents(False) - self.label_banner.setAlignment(Qt.AlignCenter) - if not app_pixmap: - app_pixmap = QPixmap(self.label_banner.pixmap()) - self.pixmap_banner = app_pixmap - self.resize_banner() - - # Carreguem la informació - self.label_info.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) - self.label_info.setWordWrap(True); - self.label_info.setText("\n" + app_info.replace(new_line, "\n")) - - # Mostrem el diàleg - if autoshow: - self.return_value = self.do_modal() - - def resizeEvent(self, newSize): - """ Mapeja l'event de canvi de mida del diàlog - --- - Map dialog size change event - """ - self.resize_banner() - - def resize_banner(self): - """ Reescala el "banner" (logo ICGC) a la mida del diàleg - --- - Resize banner (logo ICGC) to dialog size - """ - self.label_banner.setPixmap(self.pixmap_banner.scaled(self.label_banner.width(), self.label_banner.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) - - def do_modal(self): - """ Mostra el diàleg en mode modal - --- - Show dialog on modal mode - """ - self.show() - self.return_value = self.exec_() - return self.return_value +# -*- coding: utf-8 -*- +""" +******************************************************************************* +Mòdul amb classe diàleg per mostrar informació bàsica del plugin i logo el ICGC +--- +Module with a dialog class to display basic information of plugin and ICGC logo + + ------------------- + begin : 2019-01-18 + author : Albert Adell + email : albert.adell@icgc.cat +******************************************************************************* +""" + +import os +import sys + +from PyQt5 import uic +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QPalette, QColor, QFontMetrics, QPixmap +from PyQt5.QtWidgets import QStyle, QDialogButtonBox, QDialog, QApplication + +ui_about, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_about.ui')) + + +class AboutDialog(QDialog, ui_about): + """ Classe diàleg per mostrar informació bàsica del plugin i logo el ICGC + --- + Class to display basic information of plugin and ICGC logo + """ + + def __init__(self, app_name, app_info, app_icon=None, app_pixmap=None, title="Sobre", autoshow=True, new_line=" ", parent=None): + """ Inicialització del diàleg "about", cal informar de: + - app_name: Títol del diàleg + - app_icon: Icona del diàleg + - app_info: Informació a mostrar + - title: Títol de la finestra + Opcionalment: + - autoshow: Mostra el diàleg automàticament al crear-lo + - new_line: Caràcters a substituir per un canvi de linia + - parent: Especifica la finestra pare del diàleg + --- + Initialization of the "about" dialog, you need to report: +             - app_name: Title of the dialog +             - app_icon: Icon of the dialog +             - app_info: Information to show +             - title: Window title +             Optionally: +             - autoshow: Show the dialog automatically when you create it +             - new_line: Characters to be replaced by a change of line +             - parent: Specifies the parent window of the dialog + """ + QDialog.__init__(self, parent) + self.setupUi(self) + self.ui = self # Per compatibilitat QGIS2/3 + + # Canviem el títol i la icona + if not title: + title = self.windowTitle() + self.setWindowTitle("%s %s" % (title, app_name)) + if app_icon and sys.platform == "win32": + self.setWindowIcon(app_icon) + + # Escalem la imatge de logo mantenint proporcions + self.label_banner.setScaledContents(False) + self.label_banner.setAlignment(Qt.AlignCenter) + if not app_pixmap: + app_pixmap = QPixmap(self.label_banner.pixmap()) + self.pixmap_banner = app_pixmap + self.resize_banner() + + # Carreguem la informació + self.label_info.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) + self.label_info.setWordWrap(True); + self.label_info.setText("\n" + app_info.replace(new_line, "\n")) + + # Mostrem el diàleg + if autoshow: + self.return_value = self.do_modal() + + def resizeEvent(self, newSize): + """ Mapeja l'event de canvi de mida del diàlog + --- + Map dialog size change event + """ + self.resize_banner() + + def resize_banner(self): + """ Reescala el "banner" (logo ICGC) a la mida del diàleg + --- + Resize banner (logo ICGC) to dialog size + """ + self.label_banner.setPixmap(self.pixmap_banner.scaled(self.label_banner.width(), self.label_banner.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) + + def do_modal(self): + """ Mostra el diàleg en mode modal + --- + Show dialog on modal mode + """ + self.show() + self.return_value = self.exec_() + return self.return_value diff --git a/qlib3/base/anaglyphdialog.py b/qlib3/base/anaglyphdialog.py new file mode 100644 index 0000000..fd688c3 --- /dev/null +++ b/qlib3/base/anaglyphdialog.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +""" +******************************************************************************* +Mòdul amb classe diàleg gestionar series temporals de dades +--- +Module with a dialog class to manage temporal series + + ------------------- + begin : 2019-01-18 + author : Albert Adell + email : albert.adell@icgc.cat +******************************************************************************* +""" + +import os + +from PyQt5 import uic +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtCore import Qt, QPoint, QTimer +from PyQt5.QtWidgets import QDockWidget, QSlider, QApplication, QStyleOptionSlider, QToolTip + +Ui_Anaglyph, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_anaglyph.ui')) + + + + +class AnaglyphDialog(QDockWidget, Ui_Anaglyph): + """ Classe diàleg per mostrar opcions de visualitzar anaglif + --- + Class dialog to show anaglyph visualization options + """ + + def __init__(self, layer_name, update_callback=None, anaglyph_percent=100, inverted_stereo=False, \ + title="", parallax_label="", inverted_stereo_label="", autoshow=True, parent=None): + """ Inicialització del diàleg "about", cal informar de: + - layer_name: capa a modificar + Opcionalment: + - update_callback: funció a cridar quan s'actualitzen les opcions + - anaglyph_percent: Valor inicial de l'anaglif + - inverted_stereo: Valor inicial de l'estèreo invertit + - title: Títol del diàleg + - parallax_label: Etiqueta anaglif + - inverted_stereo_label: Etiqueta estèreo invertit + - autoshow: Mostra el diàleg automàticament al crear-lo + - parent: Especifica la finestra pare del diàleg + --- + Initialization of the "about" dialog, you need to report: +            - layer_name: layer to modify +            Optionally: + - update_callback: callback function to call when options are modified + - anaglyph_percent: Anaglyph initial value + - inverted_stereo: Inverted stereo initial value +            - title: Title of the dialog + - parallax_label: Anaglyph label + - inverted_stereo_label: Inverted stereo label +            - autoshow: Show the dialog automatically when you create it +            - parent: Specifies the parent window of the dialog + """ + super().__init__(parent) + self.setupUi(self) + + # Ens guardem la funció de callback si executar algun procés extern + self.update_callback = update_callback + # Configurem un temporizador per fer un refresc retardat a l'utilitzar el slider + self.parallax_timer = QTimer() + self.parallax_timer.timeout.connect(lambda:self.on_parallax_changed(delayed=0)) + + # Canviem el títol + if title: + self.setWindowTitle(title) + if layer_name: + self.update_title(layer_name) + # Canviem etiquetes si cal + if parallax_label: + self.update_parallax_label(anaglyph_percent, parallax_label) + if inverted_stereo_label: + self.checkBox_inverted_stereo.setText(inverted_stereo_label) + if inverted_stereo: + self.checkBox_inverted_stereo.setChecked(Qt.Checked if inverted_stereo else Qt.Unchecked) + + # Mostrem el diàleg + if autoshow: + self.show() + + def update_title(self, layer_name): + """ Actualitze el títol del diàleg amb el nom de la capa relacionada """ + title = self.windowTitle().split(":")[0] + self.setWindowTitle("%s: %s" % (title, layer_name)) + + def update_parallax_label(self, value=None, label=None): + """ Actualitza el valor de la etiqueta de paral·laxi """ + label_parts = self.label_parallax.text().split(": ") + if not label: + label = label_parts[0] + percent = ("%+d%%" % (value - 100)) if value is not None else label_parts[1] + self.label_parallax.setText("%s: %s" % (label, percent)) + + def set_callback(self, update_callback): + """ Actualitza la crida de refresc extern """ + self.update_callback = update_callback + + def set_enabled(self, enable=True): + """ Activa o desactiva tots els controls del diàleg """ + self.label_parallax.setEnabled(enable) + self.horizontalSlider_parallax.setEnabled(enable) + self.checkBox_inverted_stereo.setEnabled(enable) + self.label_begin.setEnabled(enable) + self.label_end.setEnabled(enable) + # Canviem el color de la barra del slider i el títol del diàleg quan està desactivat + self.horizontalSlider_parallax.setStyleSheet("" if enable else "selection-background-color: gray") + self.setStyleSheet("" if enable else "color: gray") + + def set_anaglyph(self, parallax, inverted_stereo): + """ Assigna valors a les opcions del diàleg """ + self.horizontalSlider_parallax.setValue((parallax - 80) / 4) + self.checkBox_inverted_stereo.setChecked(Qt.Checked if inverted_stereo else Qt.Unchecked) + + def get_parallax(self): + """ Retornem el valor de parallax enter entre 80 i 120 (tant per cent)""" + return self.horizontalSlider_parallax.value() * 4 + 80 + + def is_inverted_stereo(self): + """ Retornem el valor d'estèreo invertid """ + return self.checkBox_inverted_stereo.checkState() == Qt.Checked + + def on_inverted_stereo(self, inverted): + if self.update_callback: + self.update_callback(self.get_parallax(), inverted) + + def on_parallax_changed(self, value=None, delayed=1000): + parallax = self.get_parallax() + self.update_parallax_label(parallax) + # Refresh visualization delayed (to avoid excessive refresh events) + if self.update_callback: + if delayed: + self.parallax_timer.start(delayed) + else: + self.parallax_timer.stop() + self.update_callback(parallax, self.is_inverted_stereo()) diff --git a/qlib3/base/errors.py b/qlib3/base/errors.py index 37334c5..9a023b2 100644 --- a/qlib3/base/errors.py +++ b/qlib3/base/errors.py @@ -285,8 +285,9 @@ def qgis_handle_error(function): def handle_error(*args, **kwargs): try: QgsMessageLog.logMessage(f"Procés '{function.__name__}' iniciat", 'Missatges', level=Qgis.Info) - function(*args, **kwargs) + result = function(*args, **kwargs) status_message = f"Procés '{function.__name__}' finalitzat amb èxit." + return result except QgisError as e: # Error controlat (InputError, ProcessError...) title = 'Info' if e.level==Qgis.Info else ('Atenció' if e.level==Qgis.Warning else 'Error') diff --git a/qlib3/base/loginfodialog.py b/qlib3/base/loginfodialog.py index 49f1f3a..d69d67e 100644 --- a/qlib3/base/loginfodialog.py +++ b/qlib3/base/loginfodialog.py @@ -1,347 +1,347 @@ -# -*- coding: utf-8 -*- -""" -******************************************************************************* -Mòdul amb una classe diàleg per mostrar informació multilinia ---- -Module with a dialog class to display multi-line information - - ------------------- - begin : 2019-01-18 - author : Albert Adell - email : albert.adell@icgc.cat -******************************************************************************* -""" - - -import os -try: - import win32clipboard as clipboard - clipboard_available = True -except: - clipboard_available = False -try: - import utilities.email - email_available = True -except: - email_available = False - -from PyQt5 import uic -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPalette, QColor, QFontMetrics, QFont -from PyQt5.QtWidgets import QStyle, QDialogButtonBox, QDialog, QApplication, QFrame, QFileDialog, QMessageBox - -ui_loginfo, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_loginfo.ui')) - - -class LogInfoDialog(QDialog, ui_loginfo): - """ Classe diàleg per mostrar informació multilinia - --- - Dialog class to display multi-line information - """ - - mode_info = 0 - mode_warning = 1 - mode_error = 2 - - buttons_none = 0 - buttons_ok = 1 - buttons_cancel = 2 - buttons_defcancel = 4 - buttons_okcancel = (buttons_ok | buttons_cancel) - buttons_okcancel_defcancel = (buttons_ok | buttons_cancel | buttons_defcancel) - buttons_yes = 8 - buttons_no = 16 - buttons_defno = 32 - buttons_yesno = (buttons_yes | buttons_no) - buttons_yesno_defno = (buttons_yes | buttons_no | buttons_defno) - - def __init__(self, info_or_tupleinfolist, - title=u"Informació de procés", mode=mode_info, buttons=buttons_ok, - default_combo_selection=None, - extrainfo_or_tupleextrainfolist=None, extrainfohtml_or_tupleextrainfohtmllist=None, - email_button_text=None, email_subject=None, email_to=None, email_cc=None, - save_button_text=None, copy_clipboard_button_text=None, - autoshow=True, width=None, height=None, font_size=10, border=False, parent=None): - """ Inicialització del diàleg, cal especificar paràmetre amb un text d'informació o amb una - llista de tuples amb la informació. Opcionalment es pot especificar: - - title: Títol del diàleg - - mode: Mode del diàleg que canvia la icona a mostrar (mode_info, mode_warning, mode_error) - - buttons: Màscara de botons a mostrar (buttons_ok, buttons_cancel, buttons_yes ...) - - default_combo_selection: En cas de tenir una llista d'informacions, valor de la llista a mostrar per defecte - - extrainfo_or_tupleextrainfolist: Informació addicional a mostrar (botó email + shift) - - extrainfohtml_or_tupleextrainfohtmllist: Informació HTML addicional a mostrar (en emails) - - email_button_text: Text del botó que serveix per enviar informes per email - - email_subject: Asumpte del informes per email - - email_to: Destinataris dels informes per email - - email_cc: Destinataris en copia dels informes per email - - save_button_text: Text del botó de guardar informació a fitxer - - copy_clipboard_button_text: Text del botó per guardar informació al porta papers - - autoshow: Mostra automàticament el diàleg al crear-lo - - width: Amplada del diàleg - - height: Alçada del diàleg - - parent: Finestra pare del diàleg - --- - Initialization of the dialog, you need to specify a parameter with an information text or with a -            list of tuples with information. Optionally you can specify: -            - title: Dialog title -            - mode: Dialog mode that switches the icon to display (mode_info, mode_warning, mode_error) -            - buttons: Mask of buttons to show (buttons_ok, buttons_cancel, buttons_yes ...) -            - default_combo_selection: If you have a list of information, value of the list to be displayed by default -            - extrainfo_or_tupleextrainfolist: Additional information to show (email button + shift) -            - extrainfohtml_or_tupleextrainfohtmllist: Additional HTML information to show (in emails) -            - email_button_text: Text of the button used to send reports by email -            - email_subject: Subject of the reports by email -            - email_to: Receivers of the reports by email -            - email_cc: Receivers in copy of the reports by email -            - save_button_text: Text of the button to save information to file -            - copy_clipboard_button_text: Text of the button to save information to clipboard -            - autoshow: Automatically show the dialog when creating it -            - width: Dialog width -            - height: Dialog height -            - parent: Parent window of the dialog - """ - QDialog.__init__(self, parent) - self.setupUi(self) - self.ui = self # Per compatibilitat QGIS2/3 - - # Canviem el títol i la icona - self.setWindowTitle(title) - if mode == self.mode_error: - icon = QStyle.SP_MessageBoxCritical - elif mode == self.mode_warning: - icon = QStyle.SP_MessageBoxWarning - else: - icon = QStyle.SP_MessageBoxInformation - self.setWindowIcon(self.style().standardIcon(icon)) - - # Canviem la mida - if height or width: - if not height: - height = self.geometry().height() - if not width: - width = self.geometry().width() - self.resize(width, height) - - # Canviem els botons que mostrem - qt_buttons = 0 - if buttons & self.buttons_ok: - qt_buttons |= QDialogButtonBox.Ok - if buttons & self.buttons_cancel: - qt_buttons |= QDialogButtonBox.Cancel - if buttons & self.buttons_yes: - qt_buttons |= QDialogButtonBox.Yes - if buttons & self.buttons_no: - qt_buttons |= QDialogButtonBox.No - self.ui.buttonBox.setStandardButtons(qt_buttons) - if buttons & self.buttons_defcancel: - self.ui.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) - if buttons & self.buttons_defno: - self.ui.buttonBox.button(QDialogButtonBox.No).setDefault(True) - - # Mostrem o no el botó de Save - if save_button_text: - self.ui.pushButton_save.setText(save_button_text) - self.ui.pushButton_save.setMaximumWidth(QFontMetrics(self.ui.pushButton_save.font()).width(save_button_text) + 20) - self.ui.pushButton_save.setEnabled(True) - self.ui.pushButton_save.setVisible(True) - else: - self.ui.pushButton_save.setEnabled(False) - self.ui.pushButton_save.setVisible(False) - - # Motrem el botó de copiar al portapapers - if copy_clipboard_button_text: - self.ui.pushButton_clipboard.setText(copy_clipboard_button_text) - self.ui.pushButton_clipboard.setMaximumWidth(QFontMetrics(self.ui.pushButton_save.font()).width(copy_clipboard_button_text) + 20) - self.ui.pushButton_clipboard.setEnabled(clipboard_available) - self.ui.pushButton_clipboard.setVisible(True) - else: - self.ui.pushButton_clipboard.setEnabled(False) - self.ui.pushButton_clipboard.setVisible(False) - - # Botó d'email - if email_button_text: - self.ui.pushButton_email.setText(email_button_text) - self.ui.pushButton_email.setMaximumWidth(QFontMetrics(self.ui.pushButton_email.font()).width(email_button_text) + 20) - self.ui.pushButton_email.setEnabled(email_available) - self.ui.pushButton_email.setVisible(True) - else: - self.ui.pushButton_email.setEnabled(False) - self.ui.pushButton_email.setVisible(False) - self.email_subject = email_subject - self.email_to = email_to - self.email_cc = email_cc - - # Canviem el color i mida de la font de l'edit - palette = self.ui.plainTextEdit.palette() - palette.setColor(QPalette.Base, QColor('transparent')) - self.ui.plainTextEdit.setPalette(palette) - self.ui.plainTextEdit.setFont(QFont(self.ui.plainTextEdit.font().rawName(), font_size)) - if not border: - self.ui.plainTextEdit.setFrameStyle(QFrame.NoFrame) - - # Carreguem les dades - self.info_or_tupleinfolist = info_or_tupleinfolist - self.extrainfo_or_tupleextrainfolist = extrainfo_or_tupleextrainfolist - self.extrainfohtml_or_tupleextrainfohtmllist = extrainfohtml_or_tupleextrainfohtmllist - if type(info_or_tupleinfolist) is list: - self.index = 0 - self.tuple_list = info_or_tupleinfolist - self.ui.comboBox.setVisible(True) - self.ui.comboBox.setEnabled(len(info_or_tupleinfolist) > 1) - if len(info_or_tupleinfolist) > 0 and len(info_or_tupleinfolist[0]) > 1: - self.ui.comboBox.addItems([pair[0] for pair in info_or_tupleinfolist]) - combo_index = max(0, self.ui.comboBox.findText(default_combo_selection)) if default_combo_selection else 0 - self.ui.comboBox.setCurrentIndex(combo_index) - self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist[combo_index][1]) - elif type(info_or_tupleinfolist) is tuple: - self.index = 0 - self.tuple_list = [info_or_tupleinfolist] - self.ui.comboBox.setVisible(True) - self.ui.comboBox.setEnabled(False) - if len(info_or_tupleinfolist) > 0: - self.ui.comboBox.addItem(info_or_tupleinfolist[0]) - self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist[1]) - else: - self.index = None - self.tuple_list = None - self.ui.comboBox.setVisible(False) - self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist) - - # Mostrem el diàleg - self.setSizeGripEnabled(True) # Mostra la marca de resize (abaix a la dreta) - if autoshow: - self.return_value = self.do_modal() - - def update(self, index): - """ En cas de tenir una llista d'informacions, mostra la informació associada a "index" - --- - In case you have a list of information, show the information associated with "index" - """ - self.index = index - self.ui.plainTextEdit.setPlainText(self.tuple_list[index][1]) - - def get_report_info(self, html_format=False): - """ Retorna un text amb la informació mostrada en el diàleg, pot ser en format - text pla, HTML i es pot configurar els canvis de linia - --- - Returns a text with the information displayed in the dialog, it can be in -            plain text format, HTML, and you can configure line changes format - """ - if self.index: - if html_format and self.extrainfohtml_or_tupleextrainfohtmllist: - report_info = self.extrainfohtml_or_tupleextrainfohtmllist[self.index][1] - elif self.extrainfo_or_tupleextrainfolist: - report_info = self.extrainfo_or_tupleextrainfolist[self.index][1] - else: - report_info = self.info_or_tupleinfolist[self.index][1] - else: - if html_format and self.extrainfohtml_or_tupleextrainfohtmllist: - report_info = self.extrainfohtml_or_tupleextrainfohtmllist - elif self.extrainfo_or_tupleextrainfolist: - report_info = self.extrainfo_or_tupleextrainfolist - else: - report_info = self.info_or_tupleinfolist - - return report_info - - def save(self): - """ Guarda la informació del diàleg en un fitxer - --- - Saves dialog information into a file - """ - out_file, _file_type = QFileDialog.getSaveFileName(None, "Save log info", "log.txt", "Text files (*.txt)") - if not out_file: - return - report_info = self.get_report_info(html_format=False) - try: - with open(out_file, 'w', encoding='utf-8') as file: - file.write(report_info) - except Exception as e: - QMessageBox.warning(None, u"Save error", u"Error saving log\n%s" % e) - - def copy_to_clipboard(self): - """ Guarda la informació del diàleg en el portapapers - --- - Saves dialog information into clipboard - """ - if not clipboard_available: - return - clipboard.OpenClipboard() - clipboard.EmptyClipboard() - clipboard.SetClipboardText(self.ui.plainTextEdit.toPlainText()) - clipboard.CloseClipboard() - - def send_email(self): - """ Envia la informació del diàleg per email - --- - Send dialog information by email - """ - if not email_available: - return - if QApplication.keyboardModifiers() == Qt.ShiftModifier: - return self.show_extra_info() - - email_info = self.get_report_info(html_format=True) - try: - email_object = utilities.email.eMail(self.email_to, self.email_cc, self.email_subject, htmlbody = email_info, attachment_files = []) - email_object.open() - except: - QMessageBox.warning(None, u"Enviar informe", u"Error no es pot obrir el programa d'email per enviar l'informe") - - def show_extra_info(self): - """ Mostra la informació addicional en el diàleg - --- - Show extra information on dialog - """ - # Mostrem la informació extesa al diàleg - extra_info = self.get_report_info() - self.ui.plainTextEdit.clear(); - self.ui.plainTextEdit.appendPlainText(extra_info); - # Fem el diàleg més gran - extra_width = 400 - extra_height = 400 - self.resize(self.geometry().width() + extra_width, self.geometry().height() + extra_height) - self.move(self.x() - extra_width / 2, self.y() - extra_height / 2) - - def do_modal(self): - """ Mostra el diàleg en mode modal - --- - Show modal dialog - """ - self.show() - self.return_value = self.exec_() - return self.return_value - - def accept(self): - QDialog.accept(self) - - def reject(self): - QDialog.reject(self) - - def is_ok(self): - """ Retorna si s'ha premut el botó ok - --- - Return if ok button has been pressed - """ - return self.return_value == 1 - - def is_cancel(self): - """ Retorna si s'ha premut el botó cancelar - --- - Return if cancel button has been pressed - """ - return self.return_value == 0 - - def is_yes(self): - """ Retorna si s'ha premut el botó yes - --- - Return if yes button has been pressed - """ - return self.return_value == 1 - - def is_no(self): - """ Retorna si s'ha premut el botó no - --- - Return if no button has been pressed - """ - return self.return_value == 0 +# -*- coding: utf-8 -*- +""" +******************************************************************************* +Mòdul amb una classe diàleg per mostrar informació multilinia +--- +Module with a dialog class to display multi-line information + + ------------------- + begin : 2019-01-18 + author : Albert Adell + email : albert.adell@icgc.cat +******************************************************************************* +""" + + +import os +try: + import win32clipboard as clipboard + clipboard_available = True +except: + clipboard_available = False +try: + import utilities.email + email_available = True +except: + email_available = False + +from PyQt5 import uic +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QPalette, QColor, QFontMetrics, QFont +from PyQt5.QtWidgets import QStyle, QDialogButtonBox, QDialog, QApplication, QFrame, QFileDialog, QMessageBox + +ui_loginfo, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_loginfo.ui')) + + +class LogInfoDialog(QDialog, ui_loginfo): + """ Classe diàleg per mostrar informació multilinia + --- + Dialog class to display multi-line information + """ + + mode_info = 0 + mode_warning = 1 + mode_error = 2 + + buttons_none = 0 + buttons_ok = 1 + buttons_cancel = 2 + buttons_defcancel = 4 + buttons_okcancel = (buttons_ok | buttons_cancel) + buttons_okcancel_defcancel = (buttons_ok | buttons_cancel | buttons_defcancel) + buttons_yes = 8 + buttons_no = 16 + buttons_defno = 32 + buttons_yesno = (buttons_yes | buttons_no) + buttons_yesno_defno = (buttons_yes | buttons_no | buttons_defno) + + def __init__(self, info_or_tupleinfolist, + title=u"Informació de procés", mode=mode_info, buttons=buttons_ok, + default_combo_selection=None, + extrainfo_or_tupleextrainfolist=None, extrainfohtml_or_tupleextrainfohtmllist=None, + email_button_text=None, email_subject=None, email_to=None, email_cc=None, + save_button_text=None, copy_clipboard_button_text=None, + autoshow=True, width=None, height=None, font_size=10, border=False, parent=None): + """ Inicialització del diàleg, cal especificar paràmetre amb un text d'informació o amb una + llista de tuples amb la informació. Opcionalment es pot especificar: + - title: Títol del diàleg + - mode: Mode del diàleg que canvia la icona a mostrar (mode_info, mode_warning, mode_error) + - buttons: Màscara de botons a mostrar (buttons_ok, buttons_cancel, buttons_yes ...) + - default_combo_selection: En cas de tenir una llista d'informacions, valor de la llista a mostrar per defecte + - extrainfo_or_tupleextrainfolist: Informació addicional a mostrar (botó email + shift) + - extrainfohtml_or_tupleextrainfohtmllist: Informació HTML addicional a mostrar (en emails) + - email_button_text: Text del botó que serveix per enviar informes per email + - email_subject: Asumpte del informes per email + - email_to: Destinataris dels informes per email + - email_cc: Destinataris en copia dels informes per email + - save_button_text: Text del botó de guardar informació a fitxer + - copy_clipboard_button_text: Text del botó per guardar informació al porta papers + - autoshow: Mostra automàticament el diàleg al crear-lo + - width: Amplada del diàleg + - height: Alçada del diàleg + - parent: Finestra pare del diàleg + --- + Initialization of the dialog, you need to specify a parameter with an information text or with a +            list of tuples with information. Optionally you can specify: +            - title: Dialog title +            - mode: Dialog mode that switches the icon to display (mode_info, mode_warning, mode_error) +            - buttons: Mask of buttons to show (buttons_ok, buttons_cancel, buttons_yes ...) +            - default_combo_selection: If you have a list of information, value of the list to be displayed by default +            - extrainfo_or_tupleextrainfolist: Additional information to show (email button + shift) +            - extrainfohtml_or_tupleextrainfohtmllist: Additional HTML information to show (in emails) +            - email_button_text: Text of the button used to send reports by email +            - email_subject: Subject of the reports by email +            - email_to: Receivers of the reports by email +            - email_cc: Receivers in copy of the reports by email +            - save_button_text: Text of the button to save information to file +            - copy_clipboard_button_text: Text of the button to save information to clipboard +            - autoshow: Automatically show the dialog when creating it +            - width: Dialog width +            - height: Dialog height +            - parent: Parent window of the dialog + """ + QDialog.__init__(self, parent) + self.setupUi(self) + self.ui = self # Per compatibilitat QGIS2/3 + + # Canviem el títol i la icona + self.setWindowTitle(title) + if mode == self.mode_error: + icon = QStyle.SP_MessageBoxCritical + elif mode == self.mode_warning: + icon = QStyle.SP_MessageBoxWarning + else: + icon = QStyle.SP_MessageBoxInformation + self.setWindowIcon(self.style().standardIcon(icon)) + + # Canviem la mida + if height or width: + if not height: + height = self.geometry().height() + if not width: + width = self.geometry().width() + self.resize(width, height) + + # Canviem els botons que mostrem + qt_buttons = 0 + if buttons & self.buttons_ok: + qt_buttons |= QDialogButtonBox.Ok + if buttons & self.buttons_cancel: + qt_buttons |= QDialogButtonBox.Cancel + if buttons & self.buttons_yes: + qt_buttons |= QDialogButtonBox.Yes + if buttons & self.buttons_no: + qt_buttons |= QDialogButtonBox.No + self.ui.buttonBox.setStandardButtons(qt_buttons) + if buttons & self.buttons_defcancel: + self.ui.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) + if buttons & self.buttons_defno: + self.ui.buttonBox.button(QDialogButtonBox.No).setDefault(True) + + # Mostrem o no el botó de Save + if save_button_text: + self.ui.pushButton_save.setText(save_button_text) + self.ui.pushButton_save.setMaximumWidth(QFontMetrics(self.ui.pushButton_save.font()).width(save_button_text) + 20) + self.ui.pushButton_save.setEnabled(True) + self.ui.pushButton_save.setVisible(True) + else: + self.ui.pushButton_save.setEnabled(False) + self.ui.pushButton_save.setVisible(False) + + # Motrem el botó de copiar al portapapers + if copy_clipboard_button_text: + self.ui.pushButton_clipboard.setText(copy_clipboard_button_text) + self.ui.pushButton_clipboard.setMaximumWidth(QFontMetrics(self.ui.pushButton_save.font()).width(copy_clipboard_button_text) + 20) + self.ui.pushButton_clipboard.setEnabled(clipboard_available) + self.ui.pushButton_clipboard.setVisible(True) + else: + self.ui.pushButton_clipboard.setEnabled(False) + self.ui.pushButton_clipboard.setVisible(False) + + # Botó d'email + if email_button_text: + self.ui.pushButton_email.setText(email_button_text) + self.ui.pushButton_email.setMaximumWidth(QFontMetrics(self.ui.pushButton_email.font()).width(email_button_text) + 20) + self.ui.pushButton_email.setEnabled(email_available) + self.ui.pushButton_email.setVisible(True) + else: + self.ui.pushButton_email.setEnabled(False) + self.ui.pushButton_email.setVisible(False) + self.email_subject = email_subject + self.email_to = email_to + self.email_cc = email_cc + + # Canviem el color i mida de la font de l'edit + palette = self.ui.plainTextEdit.palette() + palette.setColor(QPalette.Base, QColor('transparent')) + self.ui.plainTextEdit.setPalette(palette) + self.ui.plainTextEdit.setFont(QFont(self.ui.plainTextEdit.font().rawName(), font_size)) + if not border: + self.ui.plainTextEdit.setFrameStyle(QFrame.NoFrame) + + # Carreguem les dades + self.info_or_tupleinfolist = info_or_tupleinfolist + self.extrainfo_or_tupleextrainfolist = extrainfo_or_tupleextrainfolist + self.extrainfohtml_or_tupleextrainfohtmllist = extrainfohtml_or_tupleextrainfohtmllist + if type(info_or_tupleinfolist) is list: + self.index = 0 + self.tuple_list = info_or_tupleinfolist + self.ui.comboBox.setVisible(True) + self.ui.comboBox.setEnabled(len(info_or_tupleinfolist) > 1) + if len(info_or_tupleinfolist) > 0 and len(info_or_tupleinfolist[0]) > 1: + self.ui.comboBox.addItems([pair[0] for pair in info_or_tupleinfolist]) + combo_index = max(0, self.ui.comboBox.findText(default_combo_selection)) if default_combo_selection else 0 + self.ui.comboBox.setCurrentIndex(combo_index) + self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist[combo_index][1]) + elif type(info_or_tupleinfolist) is tuple: + self.index = 0 + self.tuple_list = [info_or_tupleinfolist] + self.ui.comboBox.setVisible(True) + self.ui.comboBox.setEnabled(False) + if len(info_or_tupleinfolist) > 0: + self.ui.comboBox.addItem(info_or_tupleinfolist[0]) + self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist[1]) + else: + self.index = None + self.tuple_list = None + self.ui.comboBox.setVisible(False) + self.ui.plainTextEdit.setPlainText(info_or_tupleinfolist) + + # Mostrem el diàleg + self.setSizeGripEnabled(True) # Mostra la marca de resize (abaix a la dreta) + if autoshow: + self.return_value = self.do_modal() + + def update(self, index): + """ En cas de tenir una llista d'informacions, mostra la informació associada a "index" + --- + In case you have a list of information, show the information associated with "index" + """ + self.index = index + self.ui.plainTextEdit.setPlainText(self.tuple_list[index][1]) + + def get_report_info(self, html_format=False): + """ Retorna un text amb la informació mostrada en el diàleg, pot ser en format + text pla, HTML i es pot configurar els canvis de linia + --- + Returns a text with the information displayed in the dialog, it can be in +            plain text format, HTML, and you can configure line changes format + """ + if self.index: + if html_format and self.extrainfohtml_or_tupleextrainfohtmllist: + report_info = self.extrainfohtml_or_tupleextrainfohtmllist[self.index][1] + elif self.extrainfo_or_tupleextrainfolist: + report_info = self.extrainfo_or_tupleextrainfolist[self.index][1] + else: + report_info = self.info_or_tupleinfolist[self.index][1] + else: + if html_format and self.extrainfohtml_or_tupleextrainfohtmllist: + report_info = self.extrainfohtml_or_tupleextrainfohtmllist + elif self.extrainfo_or_tupleextrainfolist: + report_info = self.extrainfo_or_tupleextrainfolist + else: + report_info = self.info_or_tupleinfolist + + return report_info + + def save(self): + """ Guarda la informació del diàleg en un fitxer + --- + Saves dialog information into a file + """ + out_file, _file_type = QFileDialog.getSaveFileName(None, "Save log info", "log.txt", "Text files (*.txt)") + if not out_file: + return + report_info = self.get_report_info(html_format=False) + try: + with open(out_file, 'w', encoding='utf-8') as file: + file.write(report_info) + except Exception as e: + QMessageBox.warning(None, u"Save error", u"Error saving log\n%s" % e) + + def copy_to_clipboard(self): + """ Guarda la informació del diàleg en el portapapers + --- + Saves dialog information into clipboard + """ + if not clipboard_available: + return + clipboard.OpenClipboard() + clipboard.EmptyClipboard() + clipboard.SetClipboardText(self.ui.plainTextEdit.toPlainText()) + clipboard.CloseClipboard() + + def send_email(self): + """ Envia la informació del diàleg per email + --- + Send dialog information by email + """ + if not email_available: + return + if QApplication.keyboardModifiers() == Qt.ShiftModifier: + return self.show_extra_info() + + email_info = self.get_report_info(html_format=True) + try: + email_object = utilities.email.eMail(self.email_to, self.email_cc, self.email_subject, htmlbody = email_info, attachment_files = []) + email_object.open() + except: + QMessageBox.warning(None, u"Enviar informe", u"Error no es pot obrir el programa d'email per enviar l'informe") + + def show_extra_info(self): + """ Mostra la informació addicional en el diàleg + --- + Show extra information on dialog + """ + # Mostrem la informació extesa al diàleg + extra_info = self.get_report_info() + self.ui.plainTextEdit.clear(); + self.ui.plainTextEdit.appendPlainText(extra_info); + # Fem el diàleg més gran + extra_width = 400 + extra_height = 400 + self.resize(self.geometry().width() + extra_width, self.geometry().height() + extra_height) + self.move(self.x() - extra_width / 2, self.y() - extra_height / 2) + + def do_modal(self): + """ Mostra el diàleg en mode modal + --- + Show modal dialog + """ + self.show() + self.return_value = self.exec_() + return self.return_value + + def accept(self): + QDialog.accept(self) + + def reject(self): + QDialog.reject(self) + + def is_ok(self): + """ Retorna si s'ha premut el botó ok + --- + Return if ok button has been pressed + """ + return self.return_value == 1 + + def is_cancel(self): + """ Retorna si s'ha premut el botó cancelar + --- + Return if cancel button has been pressed + """ + return self.return_value == 0 + + def is_yes(self): + """ Retorna si s'ha premut el botó yes + --- + Return if yes button has been pressed + """ + return self.return_value == 1 + + def is_no(self): + """ Retorna si s'ha premut el botó no + --- + Return if no button has been pressed + """ + return self.return_value == 0 diff --git a/qlib3/base/pluginbase.py b/qlib3/base/pluginbase.py index 6c3115e..2edf470 100644 --- a/qlib3/base/pluginbase.py +++ b/qlib3/base/pluginbase.py @@ -32,8 +32,10 @@ from importlib import reload import base64 import zipfile -#import ogr -from osgeo import ogr +try: + import ogr, osr +except: + from osgeo import ogr, osr from PyQt5.QtCore import Qt, QSize, QSettings, QObject, QTranslator, qVersion, QCoreApplication, QVariant, QDateTime, QDate, QLocale, QUrl from PyQt5.QtWidgets import QApplication, QAction, QToolBar, QLabel, QMessageBox, QMenu, QToolButton @@ -42,13 +44,13 @@ from PyQt5.QtXml import QDomDocument from qgis.gui import QgsProjectionSelectionDialog, QgsAttributeDialog -from qgis.core import QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject, QgsWkbTypes, QgsRectangle, QgsContrastEnhancement +from qgis.core import QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject, QgsWkbTypes, QgsRectangle, QgsPointXY from qgis.core import QgsRasterMinMaxOrigin, QgsDataSourceUri, QgsHueSaturationFilter, QgsRasterLayer, QgsVectorLayer, QgsLayerTreeGroup -from qgis.core import QgsLayerTreeLayer, QgsLayerDefinition, QgsReadWriteContext, QgsLayoutItemMap +from qgis.core import QgsLayerTreeLayer, QgsLayerDefinition, QgsReadWriteContext, QgsLayoutItemMap, QgsContrastEnhancement from qgis.core import QgsRendererCategory, QgsCategorizedSymbolRenderer, QgsRendererRange, QgsGraduatedSymbolRenderer, QgsRenderContext, QgsRendererRangeLabelFormat from qgis.core import QgsSymbol, QgsMarkerSymbol, QgsFillSymbol, QgsBilinearRasterResampler, QgsCubicRasterResampler, QgsSimpleLineSymbolLayer from qgis.core import QgsEditorWidgetSetup, QgsPrintLayout, QgsSpatialIndex, QgsFeatureRequest, QgsMapLayer, QgsField, QgsVectorFileWriter -from qgis.core import QgsLayoutExporter, QgsFields +from qgis.core import QgsLayoutExporter, QgsFields, Qgis from qgis.utils import plugins, reloadPlugin, showPluginHelp from . import resources_rc @@ -69,6 +71,10 @@ reload(timeseriesdialog) from .timeseriesdialog import TimeSeriesDialog +from . import anaglyphdialog +reload(anaglyphdialog) +from .anaglyphdialog import AnaglyphDialog + from . import stylesdialog reload(stylesdialog) from .stylesdialog import StylesDialog @@ -230,7 +236,7 @@ def insert_at_GUI(self, menu_or_toolbar, position, names_callbacks): if entry is None: continue # Recollim les dades de usuari - eseparator, elabel, eaction, econtrol, name, callback, toggle_callback, icon, enabled, checkable, id, subentries_list = self.__parse_entry(entry) + eseparator, elabel, eaction, econtrol, name, callback, toggle_callback, icon, enabled, checkable, id, tooltip, subentries_list = self.__parse_entry(entry) # Creem el menu o toolbar if eseparator != None: @@ -300,6 +306,7 @@ def insert_at_GUI(self, menu_or_toolbar, position, names_callbacks): else: # Submenú submenu = QMenu() + submenu.setToolTipsVisible(True) self.add_to_menu(submenu, subentries_list) # Guardem el submenu (si no, si està buit, dóna problemes afegint-lo a un menú) self.menus.append(submenu) @@ -338,6 +345,11 @@ def insert_at_GUI(self, menu_or_toolbar, position, names_callbacks): action.setEnabled(False) if checkable: action.setCheckable(True) + if tooltip: + if type(action) == QWidgetAction: + action.defaultWidget().defaultAction().setToolTip(tooltip) + else: + action.setToolTip(tooltip) #Ens guardem els items de menu o toolbar, si no no apareix... self.actions.append((menu_or_toolbar, action)) @@ -349,7 +361,7 @@ def __parse_entry(self, entry): QAction --> Acció amb icona i funció a executar Altres_tipus --> Suposem que és un control (combobox, lineedit, ...) Tupla: - (Nom, [funció | (funció_activació, funció_toggle)], [icona], [enabled], [checkable], [id], [submenu_llista]) + (Nom, [funció | (funció_activació, funció_toggle)], [icona], [enabled], [checkable], [id], [tooltip], [submenu_llista]) --- Types of accepted menus / toolbars, lists of: None or "---" or "" -> separator @@ -399,6 +411,7 @@ def __parse_entry(self, entry): enabled = True checkable = False id = None + tooltip = None subentries_list = None if type(entry) != tuple: @@ -444,18 +457,24 @@ def __parse_entry(self, entry): if len(entry) > 6: if type(entry[6]) == list: subentries_list = entry[6] - # Si la entradano té callback (i no és un control) la desactivem + else: + tooltip = entry[6] + if len(entry) > 7: + if type(entry[7]) == list: + subentries_list = entry[6] + + # Si la entrada no té callback (i no és un control) la desactivem if self.disable_unmapped_gui and not separator and not label and not action and not control and not callback \ and not toggle_callback and not subentries_list: enabled = False - return separator, label, action, control, name, callback, toggle_callback, icon, enabled, checkable, id, subentries_list + return separator, label, action, control, name, callback, toggle_callback, icon, enabled, checkable, id, tooltip, subentries_list def find_action(self, id, actions_list=None): """ Cerca una acció a partir del seu objectName --- Find a action by objectName """ - if not actions_list: + if actions_list == None: actions_list = [action for menu_or_toolbar, action in self.actions] for action in actions_list: if action and action.objectName() == id: @@ -1026,10 +1045,10 @@ def refresh_map(self, wait_refreshed=False): --- Refresh the content of the map, if it is specified that you wait, the function does not return until the end event is received """ + self.map_refreshed = False self.iface.mapCanvas().refreshAllLayers() if wait_refreshed: # Espera a que es refresqui el mapa - self.map_refreshed = False while not self.map_refreshed: QApplication.instance().processEvents() @@ -1115,6 +1134,8 @@ def get_feature_attribute(self, layer, entity, field_name): --- Returns the value of a field (column) of an layer entity (row) based on its id (id prefix is passed) """ + if field_name.lower() in ('footprint', 'geometry', 'the_geom', 'geometria'): + return entity.geometry() index = layer.dataProvider().fieldNameIndex(field_name) if index < 0: return None @@ -1314,8 +1335,7 @@ def __get_attributes(self, layer_or_list_or_none, field_name_or_list, only_selec if layer: # Obtenim els elements seleccionats if only_selection: - selected_fids = set(layer.selectedFeatureIds()) - selected_features = [f for f in layer.getFeatures() if f.id() in selected_fids][:max_items] + selected_features = layer.getSelectedFeatures() else: selected_features = list(layer.getFeatures())[:max_items] # Obtenim la selecció de la capa fields_name_or_list (acceptem llista o valor) @@ -1468,24 +1488,12 @@ def set_selection(self, layer, values_list, field_name=None): # Obtenim els camps de la capa dp = layer.dataProvider() - # CANVIS QGIS2 - ##fields_names = [f.name() for f in dp.fields().values()] fields_names = [f.name() for f in dp.fields().toList()] if field_name not in fields_names: return False - field_index = fields_names.index(field_name) - fields_ids = list(dp.fields()) - field_id = fields_ids[field_index] - - # Obtenim la llista d'elements seleccionats - selected_features = [] - for feature in layer.getFeatures(): - field_value = feature[field_index] - if field_value in values_list: - selected_features.append(feature.id()) - - # Seleccionem els elements filtrats - layer.selectByIds(selected_features) + # Seleccionem pel camp indicat + expression_filter = "\"%s\" IN ('%s')" % (field_name, "', '".join([str(v).replace("\\", "\\\\") for v in values_list])) + layer.selectByExpression(expression_filter) return True def zoom_to_selection_by_id(self, layer_idprefix, scale=None, pos=0): @@ -1928,29 +1936,33 @@ def get_category_nodes(self, layer): # if not show: # self.set_visible(layer, False) - def classification_ranges_by_id(self, layer_basename, class_attribute, ranges_list, color_list=None, border_color_list=None, transparency_list=None, width_list=None, pos=0): + def classification_ranges_by_id(self, layer_basename, class_attribute, ranges_list, color_list=None, border_color_list=None, transparency_list=None, width_list=None, pos=0, suffix=None): """ Classifica els valors d'una capa per id segons la llista de rang de valors. Addicionalment se li pot passar una llista de colors, transparencia o amplada a aplicar (si és més curta que el nombre de valors, es repetiran colors utilitzant l'operador de mòdul) + suffix permet afegir un text al final de l'etiqueta de cada categoria (p.e.: unitats) --- Classify the values of a layer by id according to the list of value ranges. Additionally you can pass a list of colors to apply, transparency or width (if it is shorter than the number of values, colors will be repeated using module operator) + suffix allows the user to append a text to each of the categories (e.g.: units) """ layer = self.get_by_id(layer_basename, pos) if not layer: return False - self.classification_ranges(layer, class_attribute, ranges_list, color_list, border_color_list, transparency_list, width_list) + self.classification_ranges(layer, class_attribute, ranges_list, color_list, border_color_list, transparency_list, width_list, suffix) return True - def classification_ranges(self, layer, class_attribute, ranges_list, color_list=None, border_color_list=None, transparency_list=None, width_list=None): + def classification_ranges(self, layer, class_attribute, ranges_list, color_list=None, border_color_list=None, transparency_list=None, width_list=None, suffix=None): """ Classifica els valors d'una capa segons la llista de rang de valors. Addicionalment se li pot passar una llista de colors, transparencia o amplada a aplicar (si és més curta que el nombre de valors, es repetiran colors utilitzant mòdul) + suffix permet afegir un text al final de l'etiqueta de cada categoria (p.e.: unitats) --- Classify the values of a layer according to the list of value ranges. Additionally you can pass a list of colors to apply, transparency or width (if it is shorter than the number of values, colors will be repeated using module operator) + suffix allows the user to append a text to each of the categories (e.g.: units) """ # Afegim un categoria per cada data renderers_list = [] @@ -1971,7 +1983,9 @@ def classification_ranges(self, layer, class_attribute, ranges_list, color_list= symbol.setSize(width) else: symbol.setWidth(width) - label = f"{begin_value} - {end_value}" + label = f"{begin_value} - {end_value}" if begin_value != end_value else str(end_value) + if suffix: + label += f" {suffix}" renderers_list.append(QgsRendererRange(begin_value, end_value, symbol, label)) # Assignem la visualització per rangs a la capa @@ -1986,7 +2000,7 @@ def classification_ranges(self, layer, class_attribute, ranges_list, color_list= if not show: self.set_visible(layer, False) - def classify_by_id(self, layer_idprefix, class_attribute=None, values_list=None, color_list=None, border_color_list=None, expand=None, width=None, size=None, alpha=None, use_current_symbol=True, base_symbol=None, label_function=None, alpha_fill=None, sort=False, interpolate_colors=False, pos=0): + def classify_by_id(self, layer_idprefix, class_attribute=None, values_list=None, color_list=None, border_color_list=None, expand=None, width=None, size=None, opacity=None, use_current_symbol=True, base_symbol=None, label_function=None, alpha=None, sort=False, interpolate_colors=False, pos=0): """ Classifica els valors d'una capa per id segons la llista de valors i un camp de la capa. layer: capa a processar class_attribute: si no s'especifica, assumim que es vol partir de la classificació anterior @@ -1998,8 +2012,8 @@ def classify_by_id(self, layer_idprefix, class_attribute=None, values_list=None, use_current_symbol: utilitza la simbolització actual canviant els colors base_symbol: simbol base a utilitzar canviant els colors label_function: genera una etiqueta a partir del valor de la categoria (p.e.: canvia representació de dates: lambda x: x.toPyDate()) - alpha: aplica transparència - alpha_fill: aplica transparència només a l'emplenament (p.e.: ressalta el borde dels footprints amb transparència) + opacity: aplica opacitat a tot el símbol. Rang entre 0 (transparent) i 1 (opac) + alpha: aplica transparència al color de l'emplenament. Rang entre 0 (transparent) i 1 (opac) expand: expandeix la llegenda de la capa sort: ordena les categories pos: index de la capa amb layer_idprefix a processar @@ -2015,8 +2029,8 @@ def classify_by_id(self, layer_idprefix, class_attribute=None, values_list=None, use_current_symbol: use current symbol changing colors base_symbol: use this symbol changing colors label_function: generate a label from a category value (e.g.: tune representation of dates: lambda x: x.toPyDate()) - alpha: set transparency - alpha_fill: set transparency only to the fill (e.g.: highlight borders when footprints have transparency) + opacity: set opacity for the symbol. Range between 0 (fully transparent) and 1 (fully opaque) + alpha: set transparency only to the fill color. Range between 0 (fully transparent) and 1 (fully opaque) expand: expand layer legend sort: sort categories pos: index of layer with layer_idprefix to process @@ -2024,10 +2038,10 @@ def classify_by_id(self, layer_idprefix, class_attribute=None, values_list=None, layer = self.get_by_id(layer_idprefix, pos) if not layer: return False - self.classify(layer, class_attribute, values_list, color_list, border_color_list, expand, width, size, alpha, use_current_symbol, base_symbol, label_function, alpha_fill, sort, ininterpolate_colors) + self.classify(layer, class_attribute, values_list, color_list, border_color_list, expand, width, size, opacity, use_current_symbol, base_symbol, label_function, alpha, sort, ininterpolate_colors) return True - def classify(self, layer, class_attribute=None, values_list=None, color_list=None, border_color_list=None, expand=None, width=None, size=None, alpha=None, use_current_symbol=True, base_symbol=None, label_function=None, alpha_fill=None, sort=False, interpolate_colors=False): + def classify(self, layer, class_attribute=None, values_list=None, color_list=None, border_color_list=None, expand=None, width=None, size=None, opacity=None, use_current_symbol=True, base_symbol=None, label_function=None, alpha=None, sort=False, interpolate_colors=False): """ Classifica els valors d'una capa segons la llista de valors i un camp de la capa. layer: capa a processar class_attribute: si no s'especifica, assumim que es vol partir de la classificació anterior @@ -2040,8 +2054,8 @@ def classify(self, layer, class_attribute=None, values_list=None, color_list=Non use_current_symbol: utilitza la simbolització actual canviant els colors base_symbol: simbol base a utilitzar canviant els colors label_function: genera una etiqueta a partir del valor de la categoria (p.e.: canvia representació de dates: lambda x: x.toPyDate()) - alpha: aplica transparència - alpha_fill: aplica transparència només a l'emplenament (p.e.: ressalta el borde dels footprints amb transparència) + opacity: aplica opacitat al símbol. Rang entre 0 (transparent) i 1 (opac) + alpha: aplica transparència al color de l'emplenament. Rang entre 0 (transparent) i 1 (opac) expand: expandeix la llegenda de la capa sort: ordena les categories --- @@ -2057,8 +2071,8 @@ def classify(self, layer, class_attribute=None, values_list=None, color_list=Non use_current_symbol: use current symbol changing colors base_symbol: use this symbol changing colors label_function: generate a label from a category value (e.g.: tune representation of dates: lambda x: x.toPyDate()) - alpha: set transparency - alpha_fill: set transparency only to the fill (e.g.: highlight borders when footprints have transparency) + opacity: set opacity for the symbol. Range between 0 (fully transparent) and 1 (fully opaque) + alpha: set transparency only to the fill color. Range between 0 (fully transparent) and 1 (fully opaque) expand: expand layer legend sort: sort categories """ @@ -2069,10 +2083,11 @@ def classify(self, layer, class_attribute=None, values_list=None, color_list=Non if use_current_symbol: # Prioritzem el símbol base de la capa. Si no està definit, agafem el de la primera categoria renderer = layer.renderer() - if len(renderer.symbols(QgsRenderContext())): - base_symbol = renderer.symbols(QgsRenderContext())[0].clone() - elif hasattr(renderer, 'sourceSymbol') and renderer.sourceSymbol(): - base_symbol = renderer.sourceSymbol().clone() + if renderer: + if len(renderer.symbols(QgsRenderContext())): + base_symbol = renderer.symbols(QgsRenderContext())[0].clone() + elif hasattr(renderer, 'sourceSymbol') and renderer.sourceSymbol(): + base_symbol = renderer.sourceSymbol().clone() # Recupera el renderer o crea un de nou if hasattr(layer.renderer(), 'categories'): @@ -2152,12 +2167,12 @@ def classify(self, layer, class_attribute=None, values_list=None, color_list=Non if border_color: # pinta les línies symbol.symbolLayer(0).setStrokeColor(border_color) - if alpha is not None: + if opacity is not None: # aplica transparència al símbol sencer - symbol.setOpacity(alpha) - if alpha_fill is not None: + symbol.setOpacity(opacity) + if alpha is not None: # aplica transparència a l'emplenament - color.setAlpha(alpha_fill*100) + color.setAlphaF(alpha) symbol.symbolLayer(0).setFillColor(color) if width is not None: if type(symbol) == QgsFillSymbol: @@ -3573,7 +3588,7 @@ def add_remote_vector_files(self, remote_files_list, download_folder=None, group # Retornem la última capa return layers_list - def add_wms_t_layer(self, layer_name, url, layer_id, style, image_format, time_series_list=None, epsg=None, extra_tags="", group_name="", group_pos=None, only_one_map_on_group=False, collapsed=True, visible=True, transparency=None, saturation=None, resampling_bilinear=False, resampling_cubic=False, set_current=False): + def add_wms_t_layer(self, layer_name, url, layer_id=None, default_time=None, style="default", image_format="image/png", time_series_list=None, epsg=None, extra_tags="", group_name="", group_pos=None, only_one_map_on_group=False, collapsed=True, visible=True, transparency=None, saturation=None, resampling_bilinear=False, resampling_cubic=False, set_current=False): """ Afegeix una capa WMS-T a partir de la URL base i una capa amb informació temporal. Veure add_wms_layer per la resta de paràmetres --- @@ -3583,22 +3598,25 @@ def add_wms_t_layer(self, layer_name, url, layer_id, style, image_format, time_s # Obtenim la llista de capes temporals i la registrem associada a la url if time_series_list: if url: - default_time = dict([(layer_id, time_name) for (time_name, layer_id) in time_series_list])[layer_id] + if not default_time: + default_time = dict([(layer_id, time_name) for (time_name, layer_id) in time_series_list])[layer_id] default_layer = layer_id url_time = url else: - default_time = layer_id + if not default_time: + default_time = layer_id default_layer = layer_id url_time = dict(time_series_list)[default_layer] else: - time_series_list, default_time = self.get_wms_t_time_series(url, layer_id) + time_series_list, default_time2 = self.get_wms_t_time_series(url, layer_id) if not time_series_list: return None + default_time = default_time or default_time2 if not default_time: default_time = time_series_list[-1][0] default_layer = dict(time_series_list)[default_time] is_question_mark = url.find("?") >= 0 - url_time = "%s%stime=%s&IgnoreGetMapUrl=1" % (url, "%26" if is_question_mark else "?", default_time) + url_time = "%s%stime=%s" % (url, "%26" if is_question_mark else "?", default_time) # Obtenim el nom del temps per defecte i creem la capa time_layer_name = "%s [%s]" % (layer_name, default_time) @@ -3775,6 +3793,7 @@ def add_wms_layer(self, layer_name, url, layers_list, styles_list, image_format, uri = "url=%s&crs=EPSG:%s&format=%s&styles=%s&layers=%s" % (url, epsg, image_format, "&styles=".join(styles_list), "&layers=".join(layers_list)) if extra_tags: uri += "&%s" % extra_tags + uri += "&IgnoreGetMapUrl=1" return self.add_raster_uri_layer(layer_name, uri, "wms", group_name, group_pos, only_one_map_on_group, only_one_visible_map_on_group, collapsed, visible, transparency, saturation, set_current) @@ -3786,33 +3805,60 @@ def add_wms_url_query_layer(self, layer_name, url_query, group_name="", group_po See add_wms_layer for options """ uri = "url=%s" % url_query.lower().replace("epsg:", "epsg:").replace("srs=", "crs=").replace("?", "&") + uri += "&IgnoreGetMapUrl=1" return self.add_raster_uri_layer(layer_name, uri, "wms", group_name, group_pos, only_one_map_on_group, only_one_visible_map_on_group, collapsed, visible, transparency, saturation, set_current) - def update_wms_layer(self, layer, wms_layer, wms_time=None): + def update_wms_layer(self, layer, wms_layer=None, wms_time=None, wms_style=None): """ Actualitza la capa a llegir d'un servidor WMS --- Update WMS layer to read """ - ##print("update wms layer", wms_layer, wms_time) - # Obtenim la capa actual carregada url, current_layer, current_time = self.parse_wms_t_layer(layer) + current_style = None if url and current_layer: # Actualitzem la capa a WMS carregar (pot ser un canvi de capa (fals WMS-T) o un canvi de temps) - new_uri = layer.dataProvider().dataSourceUri() - new_uri = new_uri.replace("layers=%s" % current_layer, "layers=%s" % wms_layer) + if self.parent.check_qgis_version(31600): + # Incompatible with version 3.4 and 3.10 (not update value) + new_uri = layer.source() + else: + new_uri = layer.dataProvider().dataSourceUri() + if wms_layer: + new_uri = new_uri.replace("layers=%s" % current_layer, "layers=%s" % wms_layer) if wms_time: new_uri = new_uri.replace("time=%s" % (current_time), "time=%s" % (wms_time)) - layer.dataProvider().setDataSourceUri(new_uri) + if wms_style: + found = re.search(r"(styles=[^&]+)", new_uri, re.IGNORECASE) + if found: + current_style = found.groups()[0] + new_uri = new_uri.replace(current_style, "styles=%s" % wms_style) + else: + new_uri += "&styles=%s" % wms_style else: # Si tenim un fals WMS-T amb link a arxius raster, cal fer més refrescos... new_uri = wms_layer + + if self.parent.check_qgis_version(31600): + # Incompatible with version 3.4 and 3.10 (not updated) + layer.setDataSource(new_uri, layer.name(), "WMS", layer.dataProvider().ProviderOptions()) + else: layer.dataProvider().setDataSourceUri(new_uri) layer.dataProvider().reloadData() layer.reload() + layer.triggerRepaint() - layer.triggerRepaint() + def is_anaglyph_layer(self, layer): + """ Retorna si una capa té informació WMS anaglif + --- + Returns layer is WMS anaglyph + """ + uri = layer.source() + found = re.search(r"(styles=[^&]+)", uri.lower(), re.IGNORECASE) + if not found: + return False + anaglyph_params = found.groups()[0].split(",") + return len(anaglyph_params) == 3 def add_raster_uri_layer(self, layer_name, uri, provider, group_name="", group_pos=None, only_one_map_on_group=False, only_one_visible_map_on_group=True, collapsed=True, visible=True, transparency=None, saturation=None, set_current=False): """ Afegeix una capa raster a partir d'un URI i proveidor de dades (wms, oracle ...). Retorna la capa. @@ -3896,12 +3942,11 @@ def add_wfs_layer(self, layer_name, url, layers_list, epsg=None, filter=None, ex if not epsg: epsg = self.parent.project.get_epsg() separator = "&" if url.find("?") >= 0 else "?" - uri = "%s%sservice=WFS&version=%s&request=GetFeature&typename=%s&srsname=EPSG:%s" % (url, separator, version, ",".join(layers_list), epsg) + uri = "url=%s%sservice=WFS&version=%s&request=GetFeature&typename=%s&srsname=EPSG:%s" % (url, separator, version, ",".join(layers_list), epsg) if extra_tags: uri += "&%s" % extra_tags ds_uri = QgsDataSourceUri() ds_uri.setEncodedUri(uri) - ds_uri.setParam('url', url) # Apliquem un filtrat si cal if filter: ds_uri.setSql(filter) @@ -4706,11 +4751,15 @@ def get_composition(self, report_pathname, atlas_layer=None, atlas_filter=None, if os.path.splitext(report_pathname)[1].lower() != '.qpt': report_pathname += '.qpt' with open(report_pathname, "r") as template_file: - template_content = template_file.read() - document = QDomDocument() - document.setContent(template_content) + report_content = template_file.read() + # Modifiquem els path relatius a paths absoluts a memòria + report_path = os.path.dirname(report_pathname).replace("\\", "/") + report_content = report_content.replace('"./', '"%s/' % report_path) + report_content = report_content.replace('"../', '"%s/../' % report_path) # Creem l'objecte de l'informe + document = QDomDocument() + document.setContent(report_content) layout = QgsPrintLayout(QgsProject.instance()) layout.loadFromTemplate(document, QgsReadWriteContext(), True) @@ -5073,6 +5122,7 @@ def __init__(self, parent): # Diàlegs auxiliars i gestió de time series self.transparency_dialog = None self.time_series_dialog = None + self.anaglyph_dialog = None # Map change current layer event self.iface.layerTreeView().currentLayerChanged.connect(self.on_change_current_layer) @@ -5093,6 +5143,10 @@ def remove(self): self.transparency_dialog.close() self.iface.removeDockWidget(self.transparency_dialog) self.transparency_dialog = None + if self.anaglyph_dialog: + self.anaglyph_dialog.close() + self.iface.removeDockWidget(self.anaglyph_dialog) + self.anaglyph_dialog = None def add_shortcut_QGIS_options(self, description = "Eines QGIS", keyseq = "Ctrl+Alt+F12"): """ Afegeix un shortcut per mostrar / ocultar els menús / toolbars de QGIS @@ -5102,7 +5156,7 @@ def add_shortcut_QGIS_options(self, description = "Eines QGIS", keyseq = "Ctrl+A #Creem un shortcut per activer les opcions per defecte de QGIS self.parent.gui.add_shortcut(description, keyseq, self.toggle_QGIS_options) - def toggle_QGIS_options(self, hide_not_remove = None): + def toggle_QGIS_options(self, hide_not_remove=None): """ Mostra / Oculta els menús / toolbars de QGIS (canvia l'estat previ) --- Show / Hide QGIS menus / toolbars (change previous state) @@ -5233,18 +5287,23 @@ def add_tool_reload_plugins(self, tool_name = "&Recarregar plugins ICGC", toolba (tool_name, lambda p = plugins_id_wildcard : self.parent.debug.reload_plugins(p), QIcon(":/lib/qlib3/base/images/python.png")) ]) - def add_tool_refresh_map_and_legend(self, tool_name, remove_refresh_map): + def add_tool_refresh_map_and_legend(self, tool_name, remove_refresh_map, id="ToolRefreshMapAndLegend"): """ Afegeix o actualitza el botó de refresc per actualitzar també la llegenda --- Add or refresh the refresh button to also update the legend """ - self.action_refresh_all = QAction(QIcon(":/lib/qlib3/base/images/refresh_all.png"), tool_name, self.iface.mainWindow()) - self.action_refresh_all.triggered.connect(self.parent.refresh_all) - # Afegim el botó de la eina a la toolbar - if remove_refresh_map: - self.iface.mapNavToolToolBar().removeAction(self.iface.mapNavToolToolBar().actions()[-1]) - if self.action_refresh_all.text() not in [a.text() for a in self.iface.mapNavToolToolBar().actions()]: + self.action_refresh_all = self.parent.gui.find_action(id, self.iface.mapNavToolToolBar().actions()) + # Si no existeix creem l'acció + if not self.action_refresh_all: + self.action_refresh_all = QAction(QIcon(":/lib/qlib3/base/images/refresh_all.png"), tool_name, self.iface.mainWindow()) + self.action_refresh_all.setObjectName(id) + self.action_refresh_all.triggered.connect(self.parent.refresh_all) + # Afegim el botó de la eina a la toolbar + if remove_refresh_map: + self.iface.mapNavToolToolBar().removeAction(self.iface.mapNavToolToolBar().actions()[-1]) self.iface.mapNavToolToolBar().addAction(self.action_refresh_all) + # Registro l'acció perquè el destructor del plugin l'esborri automàticament al descarregar-lo + self.parent.gui.actions.append((self.iface.mapNavToolToolBar(), self.action_refresh_all)) def show_transparency_dialog(self, title=None, layer=None, transparency=None, show=True): """ Mostra un diàleg simplificat per escollir la transparència d'una capa @@ -5266,7 +5325,7 @@ def show_transparency_dialog(self, title=None, layer=None, transparency=None, sh else: self.transparency_dialog.hide() - def toggle_transparency_dialog(self, title=None, layer=None, transparency=None, show=True): + def toggle_transparency_dialog(self, title=None, layer=None, transparency=None): self.show_transparency_dialog(title, layer, transparency, not self.transparency_dialog.isVisible() if self.transparency_dialog else True) def show_time_series_dialog(self, layer, title=None, current_prefix="", show=True): @@ -5312,9 +5371,55 @@ def show_time_series_dialog(self, layer, title=None, current_prefix="", show=Tru if self.time_series_dialog: self.time_series_dialog.hide() - def toggle_time_series_dialog(self, layer, title=None, current_prefix="", show=True): + def toggle_time_series_dialog(self, layer, title=None, current_prefix=""): self.show_time_series_dialog(layer, title, current_prefix, not self.time_series_dialog.isVisible() if self.time_series_dialog else True) + def show_anaglyph_dialog(self, layer=None, title=None, parallax_label="", inverted_stereo_label="", show=True): + # Mostrem o ocultem el diàleg de sèries temporals + if show: + if not layer: + layer = self.parent.layers.get_current_layer() + # Obtenim els valors de paral·laxi + photo_id = "dummy" + parallax = 100 + inverted_stereo = False + found = re.search(r"styles=([^&]+)", layer.dataProvider().uri().uri().lower()) + if found: + anaglyph_params_list = found.groups()[0].split(",") + if len(anaglyph_params_list) == 3: + photo_id = anaglyph_params_list[0] + parallax = int(anaglyph_params_list[1]) + inverted_stereo = anaglyph_params_list[2] == "true" + # Si no tenim el diàleg el creem i el mostrem + update_callback = lambda parallax, inverted_stereo: self.parent.layers.update_wms_layer(layer, wms_style=",".join([photo_id, str(parallax), "true" if inverted_stereo else "false"])) + if not self.anaglyph_dialog: + self.anaglyph_dialog = AnaglyphDialog(layer.name(), update_callback, parallax, inverted_stereo, + title, parallax_label, inverted_stereo_label, True, self.iface.mainWindow()) + self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.anaglyph_dialog) + # Mapegem l'event de visibilitat per detectar quan tanquin el widget i poder refrescar + # algun botó si cal... en principi això està implementat en l'event de canvi de capa + # (que detecta si es tracta d'una capa WMS-T o no) per això emeto un un signal perquè + # s'executi + #self.anaglyph_dialog.visibilityChanged.connect(lambda dummy:self.iface.layerTreeView().currentLayerChanged.emit(self.iface.mapCanvas().currentLayer())) + else: + # Configurem el diàleg + if title: + self.anaglyph_dialog.setWindowTitle(title) + if layer: + self.anaglyph_dialog.update_title(layer.name()) + self.anaglyph_dialog.set_callback(update_callback) + self.anaglyph_dialog.set_anaglyph(parallax, inverted_stereo) + # Mostrem el diàleg + self.anaglyph_dialog.show() + # Activem els controls + self.anaglyph_dialog.set_enabled(self.parent.layers.is_anaglyph_layer(layer)) + else: + if self.anaglyph_dialog: + self.anaglyph_dialog.hide() + + def toggle_anaglyph_dialog(self, layer, title=None, current_prefix=""): + self.show_anaglyph_dialog(layer, title, current_prefix, not self.anaglyph_dialog.isVisible() if self.anaglyph_dialog else True) + def on_change_current_layer(self, layer): """ Activa o desactiva les opcions de sèries temporals / transparència segons la capa seleccionada --- @@ -5330,6 +5435,12 @@ def on_change_current_layer(self, layer): if self.transparency_dialog: if self.transparency_dialog.isVisible(): self.show_transparency_dialog(layer=layer) + # Refresh anaglyph dialog + if self.anaglyph_dialog: + is_anaglyph = layer is not None and self.parent.layers.is_anaglyph_layer(layer) + self.anaglyph_dialog.set_enabled(is_anaglyph) + if is_anaglyph and self.anaglyph_dialog.isVisible(): + self.show_anaglyph_dialog(layer=layer) def on_layer_removed(self, layer): if self.parent and self.parent.layers and self.parent.layers.time_series_dict: @@ -5415,8 +5526,12 @@ def send_email(self, mail_to, subject="", body="", copy_to="", hidden_copy_to="" Send email using system email client """ QDesktopServices.openUrl( - QUrl("mailto:%s?subject=%s&body=%s&cc=%s&bcc=%s" % ( - mail_to, subject or " ", body or " ", copy_to or " ", hidden_copy_to or " " + QUrl("mailto:%s?subject=%s%s%s%s" % ( + mail_to, + subject or " ", + ("&body=%s" % body) if body else "", + ("&cc=%s" % copy_to) if copy_to else "", + ("&bcc=%s" % hidden_copy) if hidden_copy_to else "", ), QUrl.TolerantMode)) @@ -5795,25 +5910,30 @@ def refresh_all(self): self.layers.refresh_attributes_tables() self.legend.refresh_legend() - def set_map_point(self, x, y, epsg=None, scale=None): + def set_map_point(self, x, y, epsg=None, scale=5000): """ Situa el mapa en les coordenades indicades a una determinada escala a partir d'un punt central. Reprojecta la coordenada al sistema de projecte si cal --- Locate the map in the coordinates indicated on a given scale from a central point. Reproject the coordinate to the project reference system if necessary """ - print("Coordinate: %s %s EPSG:%s" % (x, y, epsg)) + # Cal, transformem les coordenades al sistema del projecte + #print("Coordinate: %s %s EPSG:%s" % (x, y, epsg)) + if epsg and epsg != int(self.project.get_epsg()): + x, y = self.crs.transform_point(x, y, epsg) + #print("Coordinate: %s %s EPSG:%s" % (x, y, self.project.get_epsg())) - # Detectem si estem en geogràfiques o no i configurem la escala - if not scale: - scale = 0.01 if x < 100 else 1000 + ## Detectem si estem en geogràfiques o no i configurem la escala + #if not scale: + # scale = 0.01 if x < 100 else 1000 - # Calculem el rectangle a visualitzar - west = x-scale/2 - south = y-scale/2 - east = x+scale/2 - north = y+scale/2 - self.set_map_rectangle(west, north, east, south, epsg) + # Situem el centre del mapa i la escala + mc = self.iface.mapCanvas() + mc.setCenter(QgsPointXY(x, y)) + if scale: + mc.zoomScale(scale) + else: + mc.refresh() def set_map_rectangle(self, west, north, east, south, epsg=None): """ Situa el mapa en les coordenades indicades pel rectangle. @@ -5823,10 +5943,11 @@ def set_map_rectangle(self, west, north, east, south, epsg=None): Reproject the coordinates to the project reference system if necessary """ # Cal, transformem les coordenades al sistema del projecte + #print("Rectangle: %s %s %s %s EPSG:%s" % west, north, east, south, epsg) if epsg and epsg != int(self.project.get_epsg()): west, north = self.crs.transform_point(west, north, epsg) east, south = self.crs.transform_point(east, south, epsg) - print("Rectangle: %s %s %s %s EPSG:%s" % (west, north, east, south, self.project.get_epsg())) + #print("Rectangle: %s %s %s %s EPSG:%s" % (west, north, east, south, self.project.get_epsg())) # Resituem el mapa rect = QgsRectangle(west, south, east, north) # minx, miny, maxx, maxy @@ -5834,6 +5955,10 @@ def set_map_rectangle(self, west, north, east, south, epsg=None): mc.setExtent(rect) mc.refresh() + def check_qgis_version(self, version): + """ Checks QGIS version is greater than or equal to the one indicated (31004, 30400, 31600, ...) """ + return Qgis.QGIS_VERSION_INT >= version + def get_settings(self, group_name=None): self.settings.beginGroup(group_name or self.plugin_id) settings_dict = dict([(key, self.settings.value(key, None)) for key in self.settings.childKeys()]) @@ -5862,3 +5987,26 @@ def set_setting_value(self, key, value, group_name=None): else: self.settings.setValue(key, value) self.settings.endGroup(); + + #def get_setting_list(self, key, group_name=None): + # values_list = [] + # self.settings.beginGroup(group_name or self.plugin_id) + # count = self.settings.beginReadArray(key) + # for i in range(count): + # self.settings.setArrayIndex(i) + # values_list.append(self.settings.value(key)) + # self.settings.endArray() + # self.settings.endGroup(); + # return values_list + + #def set_setting_list(self, key, values_list, group_name=None): + # self.settings.beginGroup(group_name or self.plugin_id) + # if not values_list: + # self.settings.remove(key) + # else: + # self.settings.beginWriteArray(key, len(values_list)) + # for i, value in enumerate(values_list): + # self.settings.setArrayIndex(i) + # self.settings.setValue(key, value) + # self.settings.endArray() + # self.settings.endGroup(); diff --git a/qlib3/base/timeseriesdialog.py b/qlib3/base/timeseriesdialog.py index 49cedf5..ad55fdd 100644 --- a/qlib3/base/timeseriesdialog.py +++ b/qlib3/base/timeseriesdialog.py @@ -1,165 +1,122 @@ -# -*- coding: utf-8 -*- -""" -******************************************************************************* -Mòdul amb classe diàleg gestionar series temporals de dades ---- -Module with a dialog class to manage temporal series - - ------------------- - begin : 2019-01-18 - author : Albert Adell - email : albert.adell@icgc.cat -******************************************************************************* -""" - -import os - -from PyQt5 import uic -from PyQt5.QtGui import QPainter, QPen, QFont -from PyQt5.QtCore import Qt, QPoint -from PyQt5.QtWidgets import QDockWidget, QSlider, QApplication, QStyleOptionSlider, QToolTip - -Ui_TimeSeries, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_timeseries.ui')) - - -#class MySlider(QSlider): -# def __init__(self, parent=None): -# super().__init__(parent) -# self.style = QApplication.style() -# self.opt = QStyleOptionSlider() -# self.tip_offset = QPoint(10, 10) -# self.valueChanged.connect(self.show_tip) -# #self.enterEvent = self.show_tip -# #self.mouseReleaseEvent = self.show_tip - -# def paintEvent(self, event): -# """Paint log scale ticks""" -# super().paintEvent(event) -# qp = QPainter(self) -# pen = QPen() -# pen.setWidth(2) -# pen.setColor(Qt.black) - -# qp.setPen(pen) -# font = QFont('Times', 10) -# font_y_offset = font.pointSize()/2 -# qp.setFont(font) -# size = self.size() -# contents = self.contentsRect() -# db_val_list = [10, 5, 0, -5, -10, -20, -30, -40, -50, -60, -90] -# for val in db_val_list: -# if val == 10: -# y_val_fudge = 12 -# elif val == -90: -# y_val_fudge = -12 -# ##db_scaled = db_to_int(val) -# db_scaled = int(val) -# y_val = contents.height() - translate(db_scaled, 0, 1023, 0, contents.height()) -# if val == -90: -# qp.drawText(contents.x() - font.pointSize(), y_val + font_y_offset + y_val_fudge, '-oo') -# else: -# qp.drawText(contents.x() - font.pointSize(), y_val + font_y_offset + y_val_fudge,'{0:2}'.format(val)) -# qp.drawLine(contents.x() + font.pointSize(), y_val + y_val_fudge, contents.x() + contents.width(), y_val + y_val_fudge) - -# def show_tip(self, _): -# #self.initStyleOption(self.opt) -# #rectHandle = self.style.subControlRect(self.style.CC_Slider, self.opt, self.style.SC_SliderHandle, self) -# rectHandle = self.style.subControlRect(self.style.CC_Slider, None, self.style.SC_SliderHandle, self) -# pos_local = rectHandle.topLeft() + self.tip_offset -# pos_global = self.mapToGlobal(pos_local) -# QToolTip.showText(pos_global, str(self.value()), self) - -class TimeSeriesDialog(QDockWidget, Ui_TimeSeries): - """ Classe diàleg per mostrar informació bàsica del plugin i logo el ICGC - --- - Class to display basic information of plugin and ICGC logo - """ - - layer = None - time_series_list = [] - - def __init__(self, time_series_list, current_time, layer_name, update_callback=None, title=None, current_label="", autoshow=True, parent=None): - """ Inicialització del diàleg "about", cal informar de: - - title: Títol del diàleg - - layer: capa a modificar - - time_series_list: Llista de dates disponibles - Opcionalment: - - autoshow: Mostra el diàleg automàticament al crear-lo - - parent: Especifica la finestra pare del diàleg - --- - Initialization of the "about" dialog, you need to report: -             - title: Title of the dialog -             - layer: layer to modify -             - time_series_list: List of available dates -             Optionally: -             - autoshow: Show the dialog automatically when you create it -             - parent: Specifies the parent window of the dialog - """ - super().__init__(parent) - self.setupUi(self) - - # Etiqueta opcional pel valors seleccionat - self.current_value_prefix = current_label - - # Canviem el títol i la icona - if title: - self.setWindowTitle(title) - # Carreguem la sèrie temporal - self.set_time_series(time_series_list, current_time, layer_name, update_callback) - - # Mostrem el diàleg - if autoshow: - self.show() - - def set_time_series(self, time_series_list, current_time, layer_name, update_callback): - # Ens guardem la funció d'actualització de dades - self.update_callback = update_callback - - # Actualitzem el títol amb el nom de la capa - self.set_title(layer_name) - - self.time_series_list = time_series_list - # Assignem les etiquetes - self.label_begin.setText(time_series_list[0]) - self.label_end.setText(time_series_list[-1]) - self.label_current.setText(self.current_value_prefix + current_time) - # Assignem el slider - ##self.horizontalSlider = MySlider(self.horizontalSlider) - self.horizontalSlider.setTickInterval(1) - self.horizontalSlider.setMinimum(0) - self.horizontalSlider.setMaximum(len(time_series_list) - 1) - self.set_current_time(current_time) - - def set_title(self, layer_name): - title = self.windowTitle().split(":")[0] - self.setWindowTitle("%s: %s" % (title, layer_name)) - - def set_current_time(self, current_time): - # Canviem el valor quan és diferent de l'actual - new_value = self.time_series_list.index(current_time) - if self.horizontalSlider.value() != new_value: - return self.horizontalSlider.setValue(new_value) - - def get_current_time(self): - # Retornem el valor actual de la llista de time series - return self.time_series_list[self.horizontalSlider.value()] - - def on_value_changed(self, value=None): - # Modifiquem el label de temps actual - # Si entra per event de soltar slider, no tindrem "value", per això no el faig servir - self.label_current.setText(self.current_value_prefix + self.get_current_time()) - - # Volem detectar només events de click o de soltar el slider - if not self.horizontalSlider.isSliderDown(): - # Modifiquem la capa referenciada - if self.update_callback: - new_layer_name = self.update_callback(self.get_current_time()) - if new_layer_name: - self.set_title(new_layer_name) - - def set_enabled(self, enable=True): - # Activa o desactiva la barra temporal - self.horizontalSlider.setEnabled(enable) - self.label_begin.setEnabled(enable) - self.label_end.setEnabled(enable) - self.label_current.setEnabled(enable) +# -*- coding: utf-8 -*- +""" +******************************************************************************* +Mòdul amb classe diàleg gestionar series temporals de dades +--- +Module with a dialog class to manage temporal series + + ------------------- + begin : 2019-01-18 + author : Albert Adell + email : albert.adell@icgc.cat +******************************************************************************* +""" + +import os + +from PyQt5 import uic +from PyQt5.QtGui import QPainter, QPen, QFont +from PyQt5.QtCore import Qt, QPoint +from PyQt5.QtWidgets import QDockWidget, QSlider, QApplication, QStyleOptionSlider, QToolTip + +Ui_TimeSeries, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_timeseries.ui')) + + +class TimeSeriesDialog(QDockWidget, Ui_TimeSeries): + """ Classe diàleg per mostrar opcions de sèries temporals + --- + Class dialog to display temporal series options + """ + + layer = None + time_series_list = [] + + def __init__(self, time_series_list, current_time, layer_name, update_callback=None, title=None, current_label="", autoshow=True, parent=None): + """ Inicialització del diàleg "about", cal informar de: + - title: Títol del diàleg + - layer: capa a modificar + - time_series_list: Llista de dates disponibles + Opcionalment: + - autoshow: Mostra el diàleg automàticament al crear-lo + - parent: Especifica la finestra pare del diàleg + --- + Initialization of the "about" dialog, you need to report: +             - title: Title of the dialog +             - layer: layer to modify +             - time_series_list: List of available dates +             Optionally: +             - autoshow: Show the dialog automatically when you create it +             - parent: Specifies the parent window of the dialog + """ + super().__init__(parent) + self.setupUi(self) + + # Etiqueta opcional pel valors seleccionat + self.current_value_prefix = current_label + + # Canviem el títol i la icona + if title: + self.setWindowTitle(title) + # Carreguem la sèrie temporal + self.set_time_series(time_series_list, current_time, layer_name, update_callback) + + # Mostrem el diàleg + if autoshow: + self.show() + + def set_time_series(self, time_series_list, current_time, layer_name, update_callback): + # Ens guardem la funció d'actualització de dades + self.update_callback = update_callback + + # Actualitzem el títol amb el nom de la capa + self.set_title(layer_name) + + self.time_series_list = time_series_list + # Assignem les etiquetes + self.label_begin.setText(time_series_list[0]) + self.label_end.setText(time_series_list[-1]) + self.label_current.setText(self.current_value_prefix + current_time) + # Assignem el slider + ##self.horizontalSlider = MySlider(self.horizontalSlider) + self.horizontalSlider.setTickInterval(1) + self.horizontalSlider.setMinimum(0) + self.horizontalSlider.setMaximum(len(time_series_list) - 1) + self.set_current_time(current_time) + + def set_title(self, layer_name): + title = self.windowTitle().split(":")[0] + self.setWindowTitle("%s: %s" % (title, layer_name)) + + def set_current_time(self, current_time): + # Canviem el valor quan és diferent de l'actual + new_value = self.time_series_list.index(current_time) + if self.horizontalSlider.value() != new_value: + return self.horizontalSlider.setValue(new_value) + + def get_current_time(self): + # Retornem el valor actual de la llista de time series + return self.time_series_list[self.horizontalSlider.value()] + + def on_value_changed(self, value=None): + # Modifiquem el label de temps actual + # Si entra per event de soltar slider, no tindrem "value", per això no el faig servir + self.label_current.setText(self.current_value_prefix + self.get_current_time()) + + # Volem detectar només events de click o de soltar el slider + if not self.horizontalSlider.isSliderDown(): + # Modifiquem la capa referenciada + if self.update_callback: + new_layer_name = self.update_callback(self.get_current_time()) + if new_layer_name: + self.set_title(new_layer_name) + + def set_enabled(self, enable=True): + # Activa o desactiva la barra temporal + self.horizontalSlider.setEnabled(enable) + self.label_begin.setEnabled(enable) + self.label_end.setEnabled(enable) + self.label_current.setEnabled(enable) + # Canviem el color de la barra del slider i el títol del diàleg quan està desactivat + self.horizontalSlider.setStyleSheet("" if enable else "selection-background-color: gray") + self.setStyleSheet("" if enable else "color: gray") + diff --git a/qlib3/base/ui_anaglyph.ui b/qlib3/base/ui_anaglyph.ui new file mode 100644 index 0000000..02d7e44 --- /dev/null +++ b/qlib3/base/ui_anaglyph.ui @@ -0,0 +1,164 @@ + + + DockWidget + + + + 0 + 0 + 394 + 100 + + + + + 374 + 100 + + + + + 524287 + 100 + + + + DockWidget + + + + + + + + + + + -20% + + + + + + + + 0 + 30 + + + + 0 + + + 10 + + + 1 + + + 1 + + + 5 + + + 5 + + + Qt::Horizontal + + + false + + + QSlider::TicksBelow + + + + + + + +20% + + + + + + + + + + + Parallax: +0% + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Inverted stereo + + + + + + + + + + + + + + horizontalSlider_parallax + valueChanged(int) + DockWidget + on_parallax_changed() + + + 195 + 53 + + + 196 + 49 + + + + + horizontalSlider_parallax + sliderReleased() + DockWidget + on_parallax_changed() + + + 195 + 53 + + + 196 + 49 + + + + + checkBox_inverted_stereo + clicked() + DockWidget + on_inverted_stereo() + + + 290 + 77 + + + 196 + 49 + + + + + diff --git a/qlib3/base/ui_transparency.ui b/qlib3/base/ui_transparency.ui index d2f3bb0..eec2ef9 100644 --- a/qlib3/base/ui_transparency.ui +++ b/qlib3/base/ui_transparency.ui @@ -29,6 +29,12 @@ + + + 0 + 30 + + 0 diff --git a/qlib3/geofinderdialog/geofinderdialog.py b/qlib3/geofinderdialog/geofinderdialog.py index c8093a1..28e3f25 100644 --- a/qlib3/geofinderdialog/geofinderdialog.py +++ b/qlib3/geofinderdialog/geofinderdialog.py @@ -44,12 +44,12 @@ class GeoFinderDialog(QDialog, ui_geofinder): 14:'river.png', 15:'river.png' #Curs fluvial, hidrografia } - def __init__(self, geofinder_instance, geofinder_dict_list=[], title=None, columns_list=[], auto_show=False, parent=None): + def __init__(self, geofinder_instance, geofinder_dict_list=[], title=None, columns_list=[], keep_scale_text=None, default_scale=1000, auto_show=False, parent=None): """ Dialog initialization """ QDialog.__init__(self, parent) # Set up the user interface from Designer. - self.setupUi(title, columns_list) + self.setupUi(title, columns_list, keep_scale_text, default_scale) # Set up values self.geofinder = geofinder_instance @@ -61,7 +61,7 @@ def __init__(self, geofinder_instance, geofinder_dict_list=[], title=None, colum if auto_show: self.do_modal() - def setupUi(self, title, columns_list): + def setupUi(self, title, columns_list, keep_scale_text, default_scale): """ Setup the components that form the dialog """ # We Initialize the UI by associating the items in the plugin class @@ -86,6 +86,14 @@ def setupUi(self, title, columns_list): for i, col_name in enumerate(columns_list): self.tableWidget.horizontalHeaderItem(i).setText(col_name) + # Setup first scale text "keep scale" + if keep_scale_text: + self.comboBox_scale.setItemText(0, keep_scale_text) + + # Initialize default scale value + pos = max(self.comboBox_scale.findText(str(default_scale)), 0) + self.comboBox_scale.setCurrentIndex(pos) + def set_data(self, topodata_list): self.tableWidget.setRowCount(len(topodata_list)) @@ -121,19 +129,15 @@ def find(self, text, default_epsg): finally: QApplication.restoreOverrideCursor() - # If we have a rectangle, we do not have to do anything, we get the coordinates and access - if self.geofinder.is_rectangle(self.geofinder_dict_list): - # Get rectangle coordinates - self.selected = 0 - else: - # We show the found places in a dialog - self.set_data(self.geofinder_dict_list) - if not self.do_modal(): - return False - self.selected = self.get_selection_index() - if self.selected < 0: - return False - print("Selected: %s" % self.geofinder_dict_list[self.selected]['nom']) + # We show the found places in a dialog + self.comboBox_scale.setEnabled(not self.geofinder.is_rectangle(self.geofinder_dict_list)) + self.set_data(self.geofinder_dict_list) + if not self.do_modal(): + return False + self.selected = self.get_selection_index() + if self.selected < 0: + return False + print("Selected: %s" % self.geofinder_dict_list[self.selected]['nom']) return True @@ -144,4 +148,8 @@ def get_rectangle(self): return self.geofinder.get_rectangle(self.geofinder_dict_list) def get_point(self): - return self.geofinder.get_point(self.geofinder_dict_list, self.selected) \ No newline at end of file + return self.geofinder.get_point(self.geofinder_dict_list, self.selected) + + def get_scale(self): + scale = int(self.comboBox_scale.currentText()) if self.comboBox_scale.currentIndex() else None + return scale \ No newline at end of file diff --git a/qlib3/geofinderdialog/ui_geofinder.ui b/qlib3/geofinderdialog/ui_geofinder.ui index 1e32bc6..6459234 100644 --- a/qlib3/geofinderdialog/ui_geofinder.ui +++ b/qlib3/geofinderdialog/ui_geofinder.ui @@ -24,41 +24,117 @@ - - - - Name - - - - - Type - - - - - Municipality - - - - - Region - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - true - - + + + + + + Name + + + + + Type + + + + + Municipality + + + + + Region + + + + + + + + + + + 120 + 0 + + + + + Keep scale + + + + + 500 + + + + + 1000 + + + + + 2500 + + + + + 5000 + + + + + 10000 + + + + + 25000 + + + + + 50000 + + + + + 100000 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + + 120 + 0 + + + + + + + + + + diff --git a/qlib3/photosearchselectiondialog/images/photo_digital_preview.png b/qlib3/photosearchselectiondialog/images/photo_digital_preview.png new file mode 100644 index 0000000..53905e8 Binary files /dev/null and b/qlib3/photosearchselectiondialog/images/photo_digital_preview.png differ diff --git a/qlib3/photosearchselectiondialog/images/rectified_preview.png b/qlib3/photosearchselectiondialog/images/rectified_preview.png new file mode 100644 index 0000000..8c7e337 Binary files /dev/null and b/qlib3/photosearchselectiondialog/images/rectified_preview.png differ diff --git a/qlib3/photosearchselectiondialog/images/stereo_preview.png b/qlib3/photosearchselectiondialog/images/stereo_preview.png new file mode 100644 index 0000000..e8ee18d Binary files /dev/null and b/qlib3/photosearchselectiondialog/images/stereo_preview.png differ diff --git a/qlib3/photosearchselectiondialog/photosearchselectiondialog.py b/qlib3/photosearchselectiondialog/photosearchselectiondialog.py index cca79bc..1f5150c 100644 --- a/qlib3/photosearchselectiondialog/photosearchselectiondialog.py +++ b/qlib3/photosearchselectiondialog/photosearchselectiondialog.py @@ -17,26 +17,34 @@ from PyQt5.QtCore import QDateTime from PyQt5 import uic from PyQt5.QtGui import QPainter, QPen, QFont, QIcon, QColor -from PyQt5.QtCore import Qt, QPoint, QSize -from PyQt5.QtWidgets import QDockWidget, QSlider, QApplication, QStyleOptionSlider, QToolTip, QTableWidgetItem, QHeaderView, QStyle +from PyQt5.QtCore import Qt, QPoint, QSize, QTimer +from PyQt5.QtWidgets import QDockWidget, QSlider, QApplication, QStyleOptionSlider, QToolTip, QTableWidgetItem, QHeaderView, QStyle, QMenu from . import resources_rc Ui_TimeSeries, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui_%s.ui' % os.path.basename(__file__).replace("dialog.py", ""))) +class PreviewType: + NOMINAL=0 + RECTIFIED=1 + STEREO=2 + class PhotoSearchSelectionDialog(QDockWidget, Ui_TimeSeries): """ Dialog class to show results of photo search and filter it """ photo_layer = None time_series_list = [] photo_list = [] + preview_type = PreviewType.NOMINAL def __init__(self, photo_layer, time_series_list, current_time, - update_callback=None, photo_selection_callback=None, show_info_callback=None, preview_callback=None, adjust_callback=None, + update_callback=None, photo_selection_callback=None, show_info_callback=None, + preview_callback=None, rectified_preview_callback=None, stereo_preview_callback=None, adjust_callback=None, download_callback=None, request_certificate_callback=None, request_scan_callback=None, report_bug_callback=None, name_field_name="name", gsd_field_name="gsd", date_field_name="flight_date", image_field_name="image_filename", - publishable_field_name=None, available_field_name=None, autoshow=True, show_buttons_text=True, parent=None): + publishable_field_name=None, available_field_name=None, analog_field_name="analog", + autoshow=True, show_buttons_text=True, parent=None): """ Initialize time range and refresh / action callbacks """ super().__init__(parent) self.setupUi(self) @@ -48,6 +56,7 @@ def __init__(self, photo_layer, time_series_list, current_time, self.image_field_name = image_field_name self.publishable_field_name = publishable_field_name self.available_field_name = available_field_name + self.analog_field_name = analog_field_name # Set table widget properties self.tableWidget_photos.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) # col(0) és autoescalable @@ -69,6 +78,24 @@ def __init__(self, photo_layer, time_series_list, current_time, self.pushButton_request_certificate.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_certificate.png")) self.pushButton_request_scan.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_scan.png")) self.pushButton_adjust_brightness.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_brightness.png")) + # Add preview options (submenu) to preview button + preview_menu = QMenu(self); + if preview_callback: + photo_preview_action = preview_menu.addAction(self.tr("Photogram nominal orientation")) + photo_preview_action.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_preview.png")) + photo_preview_action.triggered.connect(lambda:self.update_preview_button(\ + self.preview, photo_preview_action.text(), photo_preview_action.icon())) + if rectified_preview_callback: + rectified_preview_action = preview_menu.addAction(self.tr('Rectified photogram "on the fly"')) + rectified_preview_action.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/rectified_preview.png")) + rectified_preview_action.triggered.connect(lambda:self.update_preview_button(\ + self.rectified_preview, rectified_preview_action.text(), rectified_preview_action.icon())) + if stereo_preview_callback: + stereo_preview_action = preview_menu.addAction(self.tr('Anaglyph photogram "on the fly"')) + stereo_preview_action.setIcon(QIcon(":/lib/qlib3/photosearchselectiondialog/images/stereo_preview.png")) + stereo_preview_action.triggered.connect(lambda:self.update_preview_button(\ + self.stereo_preview, stereo_preview_action.text(), stereo_preview_action.icon())) + self.pushButton_link_preview_type.setMenu(preview_menu); # Translate dialog text self.current_value_prefix = self.tr("Year: %s") @@ -93,6 +120,7 @@ def __init__(self, photo_layer, time_series_list, current_time, self.pushButton_show_info.setToolTip(self.tr("Information")) self.pushButton_link_preview.setText((" " + self.tr("View")) if show_buttons_text else "") self.pushButton_link_preview.setToolTip(self.tr("View")) + self.pushButton_link_preview_type.setToolTip(self.tr("View type")) self.pushButton_adjust_brightness.setText((" " + self.tr("Adjust\nbrightness")) if show_buttons_text else "") self.pushButton_adjust_brightness.setToolTip(self.tr("Adjust brightness")) self.pushButton_download_hd.setText((" " + self.tr("Download")) if show_buttons_text else "") @@ -101,6 +129,8 @@ def __init__(self, photo_layer, time_series_list, current_time, self.pushButton_request_certificate.setToolTip(self.tr("Request certificate")) self.pushButton_request_scan.setText((" " + self.tr("Request\nscan")) if show_buttons_text else "") self.pushButton_request_scan.setToolTip(self.tr("Request scan")) + self.label_parallax.setText(self.tr("Parallax: %+d%%") % 0) + self.checkBox_inverted_stereo.setText(self.tr("Inverted stereo")) # Configure small help in tooltip self.tableWidget_photos.setToolTip(self.tr("""When photograms list is focused you can use\n""" @@ -110,7 +140,8 @@ def __init__(self, photo_layer, time_series_list, current_time, # Update time, photo information and callbacks self.set_info(photo_layer, time_series_list, current_time, - update_callback, photo_selection_callback, show_info_callback, preview_callback, adjust_callback, + update_callback, photo_selection_callback, show_info_callback, + preview_callback, rectified_preview_callback, stereo_preview_callback, adjust_callback, download_callback, request_certificate_callback, request_scan_callback, report_bug_callback) # Hide second time slider (date range slider) @@ -120,13 +151,44 @@ def __init__(self, photo_layer, time_series_list, current_time, # Hide resolution filter (not used for the moment) self.label_quality.setVisible(False) self.comboBox_quality.setVisible(False) + # Hide stereo options + self.label_parallax.setVisible(False) + self.horizontalSlider_parallax.setVisible(False) + self.checkBox_inverted_stereo.setVisible(False) + + # Configure delayed stereo parallax change event + self.parallax_timer = QTimer() + self.parallax_timer.timeout.connect(lambda:self.on_parallax_changed(delayed=0)) # Show dialog if autoshow: self.show() + def show(self): + """ Show dialog and synchronize preview buttons size """ + super().show() + # Fix preview type button size + self.pushButton_link_preview_type.setMinimumSize(self.pushButton_link_preview_type.minimumWidth(), self.pushButton_link_preview.height()) + + def update_preview_button(self, preview_callback, preview_text, preview_icon, preview=True): + """ Changes action, icon and tooltip to preview button """ + # Remap view button function + self.pushButton_link_preview.clicked.disconnect() + self.pushButton_link_preview.clicked.connect(preview_callback) + self.pushButton_link_preview.setToolTip(preview_text) + self.pushButton_link_preview.setIcon(preview_icon) + # Enabled / Disable stereo options + stereo_visible = (preview_callback == self.stereo_preview) + self.label_parallax.setVisible(stereo_visible) + self.horizontalSlider_parallax.setVisible(stereo_visible) + self.checkBox_inverted_stereo.setVisible(stereo_visible) + # Execute current photo view + if preview: + preview_callback() + def set_info(self, photo_layer, time_series_list, current_time, - update_callback, photo_selection_callback, show_info_callback, preview_callback, adjust_callback, + update_callback, photo_selection_callback, show_info_callback, + preview_callback, rectified_preview_callback, stereo_preview_callback, adjust_callback, download_callback, request_certificate_callback, request_scan_callback, report_bug_callback): """ Store time, photo information and callbacks """ self.photo_layer = photo_layer @@ -134,6 +196,8 @@ def set_info(self, photo_layer, time_series_list, current_time, self.photo_selection_callback = photo_selection_callback self.show_info_callback = show_info_callback self.preview_callback = preview_callback + self.rectified_preview_callback = rectified_preview_callback + self.stereo_preview_callback = stereo_preview_callback self.adjust_callback = adjust_callback self.download_callback = download_callback self.request_certificate_callback = request_certificate_callback @@ -154,7 +218,9 @@ def set_info(self, photo_layer, time_series_list, current_time, # Update buttons self.pushButton_report_bug.setVisible(self.report_bug_callback is not None) self.pushButton_show_info.setVisible(self.show_info_callback is not None) - self.pushButton_link_preview.setVisible(self.preview_callback is not None) + preview_count = (1 if self.preview_callback else 0) + (1 if self.rectified_preview_callback else 0) + (1 if self.stereo_preview_callback else 0) + self.pushButton_link_preview.setVisible(preview_count > 0) + self.pushButton_link_preview_type.setVisible(preview_count > 1) self.pushButton_adjust_brightness.setVisible(self.adjust_callback is not None) self.pushButton_download_hd.setVisible(self.download_callback is not None) self.pushButton_request_certificate.setVisible(self.request_certificate_callback is not None) @@ -173,15 +239,17 @@ def get_photo_info(self, feature): return feature.id(), feature[self.name_field_name], year, datetime_text, feature[self.gsd_field_name], \ True if feature[self.image_field_name] else False, \ feature[self.publishable_field_name] if self.publishable_field_name else True, \ - feature[self.available_field_name] if self.available_field_name else True + feature[self.available_field_name] if self.available_field_name else True, \ + feature[self.analog_field_name] def reset(self, hide=True): """ Reset all information, disable controls and hide dialog""" # Delete information and disable controls self.set_info(photo_layer=None, time_series_list=[], current_time=None, update_callback=None, photo_selection_callback=None, show_info_callback=None, - preview_callback=None, adjust_callback=None, download_callback=None, - request_certificate_callback=None, request_scan_callback=None, report_bug_callback=None) + preview_callback=None, rectified_preview_callback=None, stereo_preview_callback=None, + adjust_callback=None, download_callback=None, request_certificate_callback=None, request_scan_callback=None, + report_bug_callback=None) # Hide dialog if hide: self.hide() @@ -193,6 +261,7 @@ def reset(self, hide=True): UNAVAILABLE_PHOTO_COLOR = QColor(255, 200, 200) # Icons for differents photo status DEFAULT_PHOTO_ICON = QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_preview.png") + DIGITAL_PHOTO_ICON = QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_digital_preview.png") UNPUBLISHABLE_PHOTO_ICON = QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_forbidden.png") UNSCANNED_PHOTO_ICON = QIcon(":/lib/qlib3/photosearchselectiondialog/images/photo_scan.png") UNAVAILABLE_PHOTO_ICON = QIcon(":/lib/qlib3/base/images/bug.png") @@ -206,7 +275,7 @@ def update_photos(self): # Update tableWidget with photo_list data self.tableWidget_photos.blockSignals(True) self.tableWidget_photos.setRowCount(0) - for id, name, year, flight_datetime_text, gsd, image_available, publishable, available in self.photo_list: + for id, name, year, flight_datetime_text, gsd, image_available, publishable, available, analog in self.photo_list: if year is not None and year in time_range_list and gsd is not None and gsd >= min_res and gsd < max_res: if not available: color = self.UNAVAILABLE_PHOTO_COLOR @@ -220,6 +289,10 @@ def update_photos(self): color = self.UNSCANNED_PHOTO_COLOR icon = self.UNSCANNED_PHOTO_ICON tooltip = self.tr("Scan required") + elif not analog: + color = self.DEFAULT_PHOTO_COLOR + icon = self.DIGITAL_PHOTO_ICON + tooltip = self.tr("Available") else: color = self.DEFAULT_PHOTO_COLOR icon = self.DEFAULT_PHOTO_ICON @@ -227,7 +300,7 @@ def update_photos(self): row = self.tableWidget_photos.rowCount() self.tableWidget_photos.insertRow(row) item = QTableWidgetItem(name) - item.setData(Qt.UserRole, (id, image_available, available, publishable)) + item.setData(Qt.UserRole, (id, image_available, available, publishable, analog)) item.setBackground(color) item.setToolTip(tooltip) item.setIcon(icon) @@ -259,6 +332,9 @@ def update_photos(self): self.label_end_range.setEnabled(enable) self.label_current.setEnabled(enable) self.tableWidget_photos.setEnabled(enable) + self.label_parallax.setEnabled(enable) + self.horizontalSlider_parallax.setEnabled(enable) + self.checkBox_inverted_stereo.setEnabled(enable) # Simulate update selection signal (and enable/disable selection dependent buttons) self.on_photo_changed() @@ -344,15 +420,13 @@ def on_range_clicked(self, enabled): def on_value_changed(self, value=None): """ Mapped event to update filtered photograms list when change current year """ - if not self.horizontalSlider.isSliderDown(): - self.update_filter() + self.update_filter(self.horizontalSlider.isSliderDown()) def on_range_value_changed(self, value=None): """ Mapped event to update filtered photograms list when change current year range """ - if not self.horizontalSlider_range.isSliderDown(): - self.update_filter() + self.update_filter(self.horizontalSlider_range.isSliderDown()) - def update_filter(self): + def update_filter(self, only_label=False): """ Update photograms list applying year and resolution filters """ # Update current years label current_time, current_range = self.get_current_time_range() @@ -360,6 +434,8 @@ def update_filter(self): self.label_current.setText(self.current_value_prefix % ("%s - %s" % (str(current_time), str(current_range)))) else: self.label_current.setText(self.current_value_prefix % str(current_time)) + if only_label: + return # Update photograms list self.update_photos() @@ -375,21 +451,21 @@ def on_quality_changed(self, index): self.update_photos() def get_selected_photo_id(self): - photo_id, _image_available, _publishable, _available = self.get_selected_photo_info() + photo_id, _image_available, _publishable, _available, _analog = self.get_selected_photo_info() return photo_id def get_selected_photo_info(self): """ Return current selected photogram id """ items_list = self.tableWidget_photos.selectedItems() if not items_list: - return None, None, None, None + return None, None, None, None, None row = items_list[0].row() item = self.tableWidget_photos.item(row, 0) - photo_id, image_available, available, publishable = item.data(Qt.UserRole) + photo_id, image_available, available, publishable, analog = item.data(Qt.UserRole) image_available = item.background() not in [self.UNSCANNED_PHOTO_COLOR, self.UNAVAILABLE_PHOTO_COLOR] available = item.background() != self.UNAVAILABLE_PHOTO_COLOR publishable = item.background() != self.UNPUBLISHABLE_PHOTO_COLOR - return photo_id, image_available, publishable, available + return photo_id, image_available, publishable, available, analog def get_selected_photo_name(self): """ Return current selected photogram name """ @@ -408,7 +484,7 @@ def select_photo(self, photo_id, year): if photo_id is not None: # Search photo_id row for i in range(self.tableWidget_photos.rowCount()): - photo_id2, _image_available, _publishable, _available = self.tableWidget_photos.item(i, 0).data(Qt.UserRole) + photo_id2, _image_available, _publishable, _available, _analog = self.tableWidget_photos.item(i, 0).data(Qt.UserRole) if photo_id2 == photo_id: row = i break @@ -424,30 +500,64 @@ def select_photo(self, photo_id, year): def on_photo_changed(self): """ Mapped event to update photo layer selection when change selected photogram """ - photo_id, image_available, publishable, available = self.get_selected_photo_info() + # Select phootogram + photo_id, image_available, publishable, available, analog = self.get_selected_photo_info() if self.photo_selection_callback: self.photo_selection_callback(photo_id) - + # Select year + current_time, current_range = self.get_current_time_range() + if self.update_callback and current_time: + new_layer_name = self.update_callback(current_time, current_range) + + # Select "photo view" type for analog photograms (disable rectified modes) + if analog: + self.update_preview_button(self.preview, + self.pushButton_link_preview_type.menu().actions()[0].text(), + self.pushButton_link_preview_type.menu().actions()[0].icon(), + False) + # Enable or disable option for photogram enable = photo_id is not None + nominal_preview = (self.preview_type == PreviewType.NOMINAL) self.pushButton_report_bug.setEnabled(enable and image_available) self.pushButton_show_info.setEnabled(enable) self.pushButton_link_preview.setEnabled(enable and image_available) + self.pushButton_link_preview_type.setEnabled(enable and image_available) + self.pushButton_link_preview_type.menu().actions()[1].setEnabled(not analog) + self.pushButton_link_preview_type.menu().actions()[2].setEnabled(not analog) self.pushButton_adjust_brightness.setEnabled(enable and image_available) - self.pushButton_download_hd.setEnabled(enable and image_available and publishable) + self.pushButton_download_hd.setEnabled(enable and image_available and publishable and nominal_preview) self.pushButton_request_certificate.setEnabled(enable and image_available and publishable) self.pushButton_request_scan.setEnabled(enable and not image_available and available) - + def show_info(self): """ Mapped event to show photo information when push button """ photo_id = self.get_selected_photo_id() if self.show_info_callback and photo_id: self.show_info_callback(photo_id) - + def preview(self): """ Mapped event to load photo raster when push button """ photo_id = self.get_selected_photo_id() if self.preview_callback and photo_id: self.preview_callback(photo_id) + self.preview_type = PreviewType.NOMINAL + self.on_photo_changed() + + def rectified_preview(self): + """ Mapped event to load rectified photo raster when push button """ + photo_id = self.get_selected_photo_id() + if self.rectified_preview_callback and photo_id: + self.rectified_preview_callback(photo_id) + self.preview_type = PreviewType.RECTIFIED + self.on_photo_changed() + + def stereo_preview(self): + """ Mapped event to load stereo photo raster when push button """ + photo_id = self.get_selected_photo_id() + if self.stereo_preview_callback and photo_id: + self.stereo_preview_callback(photo_id) + self.preview_type = PreviewType.STEREO + self.on_photo_changed() def adjust(self): photo_id = self.get_selected_photo_id() @@ -481,7 +591,7 @@ def report_bug(self): def on_table_key_press(self, event): """ Mapped table keyPress event to change current year with cursors and load preview photo raster """ if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter: - self.preview() + self.pushButton_link_preview.click() self.tableWidget_photos.setFocus() elif event.key() == Qt.Key_Left: self.horizontalSlider.setValue(self.horizontalSlider.value() - 1) @@ -500,3 +610,23 @@ def on_slider_key_press(self, event, widget): self.tableWidget_photos.selectRow(rows_list[0].row()+1 if rows_list else 0) else: self.horizontalSlider.__class__.keyPressEvent(widget, event) + + def on_parallax_changed(self, value=None, delayed=1000): + parallax = self.get_parallax() - 100 + self.label_parallax.setText(self.tr("Parallax: %+d%%") % parallax) + # Refresh visualization delayed (to avoid excessive refresh events) + if delayed: + self.parallax_timer.start(delayed) + else: + self.parallax_timer.stop() + self.pushButton_link_preview.click() + + def on_inverted_stereo(self, inverted): + # Refresh visualization + self.pushButton_link_preview.click() + + def get_parallax(self): + return self.horizontalSlider_parallax.value() * 4 + 80 + + def is_inverted_stereo(self): + return self.checkBox_inverted_stereo.checkState() == Qt.Checked diff --git a/qlib3/photosearchselectiondialog/resources.qrc b/qlib3/photosearchselectiondialog/resources.qrc index 6761152..46697b6 100644 --- a/qlib3/photosearchselectiondialog/resources.qrc +++ b/qlib3/photosearchselectiondialog/resources.qrc @@ -2,9 +2,12 @@ images/photo_brightness.png images/photo_certificate.png + images/photo_digital_preview.png images/photo_download.png images/photo_forbidden.png images/photo_preview.png images/photo_scan.png + images/rectified_preview.png + images/stereo_preview.png diff --git a/qlib3/photosearchselectiondialog/resources_rc.py b/qlib3/photosearchselectiondialog/resources_rc.py index 475c2a0..ad79d4b 100644 --- a/qlib3/photosearchselectiondialog/resources_rc.py +++ b/qlib3/photosearchselectiondialog/resources_rc.py @@ -9,6 +9,169 @@ from PyQt5 import QtCore qt_resource_data = b"\ +\x00\x00\x04\xa2\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7\x6f\ +\xa8\x64\x00\x00\x04\x37\x49\x44\x41\x54\x78\x5e\xed\xd8\x5f\x48\ +\x5b\x57\x18\x00\xf0\x2f\x4d\xea\x70\x1b\x41\xfb\xa0\x18\xff\x83\ +\xd2\x07\x99\x06\xa7\xe0\x1c\x03\xf1\xdf\xfc\x03\x22\x41\x7d\x48\ +\x3b\x9b\x49\x27\xc8\x66\xa3\xe0\xc4\x32\xac\x1b\xab\x32\x32\x64\ +\x62\x98\x8a\x84\x61\xbb\xb0\x07\x1f\x02\x3e\xcc\xc2\x54\x1c\x6c\ +\x2b\x9d\x46\x6a\xa4\xce\x07\x5f\x26\x53\x41\x7c\xe8\xcc\xe8\x86\ +\xd1\xe4\xee\x3b\xf1\x9b\x25\xf1\x06\x93\xd4\x64\xd0\x7c\x3f\xb8\ +\xdc\x9c\xef\x9e\x7b\xcf\x39\xdf\xbd\xf7\xe4\xde\x0b\x8c\x31\xc6\ +\x18\x63\x8c\x31\xc6\x18\x63\xb1\x46\x49\xeb\xa0\xb5\xb5\xb5\x5d\ +\x95\x24\xe9\xd3\xcc\xcc\xcc\x92\x8a\x8a\x8a\x3f\x1c\x0e\xc7\x53\ +\xda\xf4\xbf\x68\x68\x68\xb8\x1a\x17\x17\x77\x2b\x3b\x3b\xfb\x83\ +\x84\x84\x04\xc7\xfe\xfe\x7e\x64\xfa\xd3\xde\xde\xfe\xaa\x56\xab\ +\xbd\xdd\xdd\xdd\xed\xc2\x46\xa4\xad\xad\x2d\xc9\x68\x34\xba\xca\ +\xcb\xcb\x3f\xa2\x2a\x51\x85\x27\x41\x51\x56\x56\x66\xec\xe9\xe9\ +\x71\xed\xed\xed\x49\x4e\xa7\x53\xea\xbf\x73\xc7\x55\x55\x55\x75\ +\x1f\x97\xd7\xa8\xda\xc5\x28\x2a\x2a\xaa\x6d\x6c\x6c\xfc\x7d\x65\ +\x65\x45\xf2\x78\x3c\xd8\xf6\x09\xf1\x7b\x74\x74\x54\xaa\xaf\xaf\ +\xbf\x46\x55\xa3\x26\x2f\x2f\xef\x5d\xb3\xd9\xec\xd3\x1f\x61\x73\ +\x73\x53\x6a\x6d\x6d\xfd\xb3\xb0\xb0\xd0\x40\x55\xc3\x67\x30\x18\ +\xde\xc0\x2c\xcf\x4e\x4d\x4d\x49\x6e\xb7\x9b\x9a\xf0\x75\x7c\x7c\ +\x2c\xe9\x74\xba\xb5\xe6\xe6\xe6\x90\x6f\xa7\x70\x75\x76\x76\xbe\ +\x82\x27\x64\x53\xb4\x2d\x47\xf4\x75\x66\x66\x46\xaa\xa9\xa9\xf9\ +\x15\xaf\x86\xb7\x69\xb7\xe0\xe1\x8e\xea\xd2\xd2\xd2\x91\xbe\xbe\ +\x3e\xf7\xc1\xc1\x01\x1d\x36\x30\xab\xd5\x2a\xe9\xf5\xfa\x37\x69\ +\xf7\x88\x2b\x28\x28\xc8\xb3\x58\x2c\xd4\x7a\x60\x87\x87\x87\x92\ +\xc9\x64\xf2\x60\xfd\x11\xbc\x2a\x52\x69\x77\x1f\x0a\x5a\x7b\xe1\ +\x7d\x7e\x79\x61\x61\xa1\x1e\x07\xff\x6d\x6f\x6f\xef\xeb\xb9\xb9\ +\xb9\xa0\x50\xf8\x54\x91\x65\xb7\xdb\x61\x60\x60\xa0\xbb\xab\xab\ +\xeb\x1e\x85\x22\x0a\x13\x7e\xa3\xa3\xa3\xe3\xab\x92\x92\x12\x8a\ +\x04\x86\x79\x80\xdd\xdd\x5d\x18\x1c\x1c\x7c\xb6\xbe\xbe\xfe\x59\ +\x7e\x7e\xfe\xc8\xe4\xe4\xe4\x11\x6d\xf6\x4d\x40\x52\x52\x52\x25\ +\x56\x98\xc3\x25\xa8\x81\xff\xc7\xe5\x72\x01\x5e\x76\x10\x1f\x1f\ +\x4f\x91\xc8\xc2\x33\xeb\xed\x1f\xce\xfe\x14\x09\xce\xc6\xc6\x06\ +\xe0\x04\x7e\x6d\x79\x79\xf9\x3b\x0a\x9d\x51\x39\x3f\x3f\xef\x9d\ +\x58\x5e\xc6\x05\x07\x2e\x89\x31\x9e\x0c\xf5\xc4\x25\x5a\xfb\x10\ +\xd9\x7d\x59\x17\x7f\xb2\x09\x88\x25\xfe\x29\x11\xb7\xc0\x1c\x3e\ +\xe1\x51\x11\xe0\xe8\xe8\x08\x56\x1f\x3f\x06\xfc\xcb\xa1\x48\x68\ +\x32\xb3\xb2\x40\xa3\xd1\x50\x29\x34\xde\xb6\x57\x57\xc3\x6e\x3b\ +\x0b\xdb\x4e\x49\x49\xa1\x12\x00\x3e\xc7\x88\x67\x9a\x2a\xfc\x39\ +\x7f\x12\x39\x27\x01\x62\x06\x35\xf4\xdf\x05\x6b\xb2\x16\xaf\x15\ +\x95\x37\x16\x2a\xf5\x6f\x0f\x61\xad\xaf\x1d\xd2\xd3\xd3\x29\x12\ +\x1c\xd1\x76\xef\x8d\xeb\xf0\xd6\x93\x47\x70\x59\xe6\xd2\x0d\xc6\ +\xe2\x3f\x6e\x30\x3e\xf8\x11\xf0\xb1\xdd\x5b\x0e\x2b\x01\xf9\x1f\ +\x7f\x0e\x4f\xf4\xfd\x62\x62\xf0\xc6\x42\x75\xc9\xf1\x33\x3c\xd0\ +\xfc\x0d\xd5\xd5\xd5\x14\x09\x8e\x38\xeb\x9f\xbc\x53\x0c\x5f\xa8\ +\xf1\xde\xa5\x58\xa8\x7e\x7a\xfa\x17\x3c\xbb\xfb\x35\xd4\x50\xdb\ +\x72\x09\x88\xca\x1c\x10\xee\x00\xa2\x21\xe6\x27\x41\x4e\x00\xad\ +\x63\x16\x27\x80\xd6\x31\x8b\x13\x40\xeb\x73\x88\x77\x88\xe8\x93\ +\x5e\xf0\x0f\x54\xf4\xfa\xbc\x23\xf8\x6f\x3f\xf3\x20\x74\x6b\xe8\ +\x4b\x98\x54\x69\xf0\x60\xe1\x7d\xf0\x49\xda\x5a\x83\x95\x81\x2e\ +\x48\x4e\x4e\xa6\xc8\x73\xe2\xf8\x72\x2f\x28\x82\xd8\xd6\xdf\xf9\ +\x21\xe4\xfc\xf2\x03\x84\xf7\x0c\x0a\xb0\xa4\x88\x83\xdb\xdf\x2f\ +\x9c\x3e\x0e\x87\xfc\x24\x28\x88\xf7\x7c\xf1\x41\xc1\x83\xeb\x70\ +\x24\x5e\xb9\x02\x6a\xb5\x9a\x4a\xcf\x89\x01\x9a\xcd\x66\x48\x4d\ +\x4d\x05\x9d\x4e\x27\x9b\x88\xd3\xb6\x3d\x1e\x8a\x84\x26\x31\x31\ +\xd1\xa7\x6d\xb9\x04\xf8\x13\x09\xc0\xbe\x45\x96\x78\x37\x1f\x1b\ +\x1b\x3b\xc6\xc1\x5f\xaf\xad\xad\x9d\xb2\xd9\x6c\xb4\x25\xb2\xec\ +\x76\xfb\x99\xef\x01\xfe\x22\x9e\x00\x1a\xbc\x2b\x2d\x2d\x4d\x2f\ +\x1a\xc4\x90\xa2\xae\xae\xee\x5e\x34\x92\x20\x97\x80\xa8\xfe\x0b\ +\x60\x1f\x60\x62\x62\xc2\x3d\x34\x34\x64\xd8\xde\xde\xf6\x7e\x96\ +\xc2\x4b\x5f\x2a\x2e\x2e\x7e\xdf\x62\xb1\xdc\xc7\x24\x78\xeb\x44\ +\x93\xcf\x8d\xa7\x54\x2a\x2b\xc7\xc7\xc7\xe7\xb0\x43\x14\xb9\x58\ +\x8b\x8b\x8b\x30\x3c\x3c\xfc\xde\xce\xce\x8e\x95\x42\xa7\xa6\xa7\ +\xa7\x95\xdf\xa0\x96\x96\x96\x56\xad\x56\x1b\x70\x72\x7c\x11\xe2\ +\x9b\xa0\x5e\xaf\x0f\x3c\x09\x36\x35\x35\xe5\xa8\x54\xaa\x9b\x54\ +\xbc\x70\x4e\xa7\x73\x69\x76\x76\xd6\x46\x45\x59\xd8\x87\x9b\xd8\ +\x87\x1c\x2a\x5e\xb8\x8c\x8c\x0c\x9b\xc9\x64\x5a\xa2\x22\x63\x8c\ +\x31\xc6\x18\x63\x8c\x31\xc6\x18\x63\xb1\x05\xe0\x5f\xd9\x8c\x8e\ +\xf4\x16\xcd\x28\x4c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\ +\x82\ +\x00\x00\x05\x36\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x16\xb7\x00\x00\x16\xb7\x01\x5a\x8b\ +\x7b\x20\x00\x00\x04\xcb\x49\x44\x41\x54\x78\x5e\xed\x9b\x59\xc8\ +\x75\x53\x18\x80\x3f\xf3\x4c\x64\xce\x10\x91\x39\xe5\x02\x17\x08\ +\x45\x11\x32\x24\xdc\x28\x12\x19\xae\x64\x2a\x53\x29\x37\x4a\x21\ +\x43\xe6\x12\x17\x72\x27\x94\xbf\x50\x8a\xa4\x94\x79\x0c\x91\x21\ +\x43\xc6\xcc\xe3\xf3\x9c\xbd\x97\x56\xbb\x7d\xce\xd9\x6b\xef\xf5\ +\x9f\x75\x74\xce\x53\x4f\x7b\x7f\xfb\xdf\xdf\xf9\xd6\x7a\xcf\x5e\ +\xd3\xbb\xf6\xbf\x52\x90\x03\xf0\x13\x7c\x0b\x77\xf0\xc2\xa2\x71\ +\x1b\xfe\x53\x7b\xb1\x17\x4a\xb0\x66\x7d\x2c\xc1\xba\xf5\x51\xe2\ +\xf3\x99\x52\x32\x00\x73\xc1\x32\x00\xf5\x71\x61\x59\x06\xa0\x3e\ +\x2e\x2c\x29\x01\xd8\x14\xff\x2f\x01\xdb\x0c\xd7\xa8\x4e\x27\xd3\ +\xb5\x42\x97\xe2\x77\xf8\x2a\x6e\xef\x85\x0c\x7c\x59\x1f\x25\x3e\ +\x1f\x82\xf5\xb9\x1d\x2d\xeb\x73\xb8\x36\x66\xe1\x05\x0c\x93\x96\ +\x77\x30\x47\x10\xfc\x96\x6e\xc2\xeb\x70\x1d\x2f\x0c\xc4\xca\xdf\ +\x8d\xa1\x9c\xba\x33\x66\xe1\x4c\xfc\x1b\x73\x07\x21\x17\x6d\x95\ +\x7f\x14\x3b\x35\x83\xae\x9c\x87\xf3\x18\x84\xb6\xca\x3f\x8e\xeb\ +\xe1\x54\x52\x23\x64\x10\xee\xc0\xf0\x7b\xef\xe2\x11\xf8\xd9\xe8\ +\xa7\xe9\xf8\x7b\xbb\xe3\xde\xb8\x0b\xda\x0c\x6c\xa7\x3f\xe2\xe7\ +\xf8\x36\xbe\x82\xbf\x61\x17\xac\xfc\x9d\x78\xce\xe8\xa7\x8a\x27\ +\xf0\x64\xec\xfa\x19\xc9\xb4\x3d\x09\xdb\xe2\x38\xac\xf4\x91\x78\ +\x1f\x1a\xa8\xf8\x9b\x6a\xf3\x67\x7c\x12\xcf\xc2\x4d\x70\x1c\x7e\ +\xee\x5d\x18\xff\x6e\xe7\x6f\x7e\x28\xcd\x20\xdc\x88\x6d\x9c\x8a\ +\x8e\x1c\x71\x21\x53\xfc\x16\xed\x24\x1d\x82\x9b\x1c\x84\xf1\xbd\ +\x33\xab\x7c\xc0\x20\xfc\x85\xfe\xf1\x0b\xbc\x10\xb1\x2b\x3e\x85\ +\x71\x01\x83\x3e\xee\xcf\xe3\x03\xf8\x50\x7d\x6d\x9a\x9f\xe2\x49\ +\x18\xb3\x13\xfa\xb4\xf8\xef\x33\xaf\x7c\xc0\xa4\x86\x7d\x40\xcc\ +\x89\xe8\x38\x1c\x57\xe0\x27\xbc\x07\xbd\x37\x5e\xfa\xee\x8b\xf1\ +\x7d\xd3\xbc\x15\xe3\xb1\x7d\x37\x3c\x16\x73\x0c\xa3\x59\x38\x1f\ +\xc3\x53\xa1\x7f\xe2\x2d\xb8\x0d\xb6\x91\x1a\x00\x7d\x0c\x37\xc0\ +\xb9\xc3\x4e\x2b\xee\x17\x3e\xc0\x03\x71\x12\x7d\x02\xa0\x8e\xf1\ +\xd9\x66\x79\x39\x38\x0c\xff\xc0\x50\x40\xdb\xf8\x16\x38\x8d\xbe\ +\x01\x50\x67\x91\x73\xc1\xe6\x68\x72\x33\x14\xec\x45\xdc\x18\xbb\ +\x30\x24\x00\x3e\x6d\x27\x60\x71\x9c\x18\x85\x42\xd9\x5b\x8f\x6b\ +\xef\x6d\x0c\x09\x80\x7e\x8c\x1b\x61\x31\xf6\x40\x3b\xba\x50\xa0\ +\xa3\x30\x85\xa1\x01\xd0\x2b\xb1\x18\xce\xee\x42\x41\x1e\xf1\x42\ +\x22\x39\x02\xf0\x15\x16\x19\x15\x9c\xa6\x3a\xbe\x5b\x08\xdb\xa3\ +\x95\x49\x25\x47\x00\xf4\x0c\xec\x85\x8b\x89\xbe\xd8\x01\x6d\x58\ +\x9d\xae\x3c\x8b\xaf\x57\xa7\x45\x38\xad\x3e\x26\x33\x24\x00\x2e\ +\x70\x02\x0f\xd7\xc7\x52\x1c\x8e\xbd\xe6\x05\x43\x02\xe0\x62\x24\ +\xf0\x74\x7d\x2c\x85\xcb\xea\x3d\xab\xd3\x34\xfa\x06\x60\x2d\x74\ +\x1e\x2e\x2e\x48\xde\xab\x4e\x8b\xe2\x88\x94\x8c\x6b\xea\x7d\xf0\ +\x7a\x9c\xb4\xf6\xfe\x05\x5d\x96\x3a\xc9\x91\xad\x30\x24\x32\x4d\ +\x62\xec\x55\x9d\x26\x63\x27\xf8\x5a\x75\x3a\x98\x0b\xd1\x84\xa8\ +\x38\x05\xbf\x06\x27\x8d\x0e\xae\x4a\x47\x43\xe8\x2a\x6c\xeb\x59\ +\x9b\xbe\x84\x01\xb3\x39\xe1\x7a\x08\x4a\x1f\x72\x8d\x02\x7a\x19\ +\x06\x2c\x6b\xdb\x3d\x4d\x57\xd9\x04\xdc\x9f\xef\x42\x7c\x9f\xf3\ +\xfe\x40\xb1\x9d\xdd\x06\x71\x99\x3a\xd7\xc9\x26\x60\x10\x8e\xc6\ +\x49\x4d\xc0\x76\xee\x93\x12\xfe\x88\xf7\xfe\x50\x9d\x8e\xd6\x01\ +\x3b\x56\xa7\xc9\xe4\x6c\x02\xe6\x05\xef\xad\x4e\x47\xf9\x01\xeb\ +\x14\x86\xe9\x36\x6c\x02\xd6\xa9\x37\xf6\x01\x3e\x46\x4e\x82\xba\ +\x2e\x7e\x9a\xe4\x6c\x02\xcd\xc4\x4c\x27\x86\x0c\x83\x6f\xd4\x47\ +\x9f\xa2\x78\x48\x2c\xc5\x9b\xf5\x31\x89\x21\x01\x70\xf6\x17\x30\ +\x2d\x55\x12\x47\xa2\x2f\xaa\xd3\x34\x86\x04\xc0\xfc\x7b\xc0\xb9\ +\x78\xc9\xbc\x9c\x49\xd1\x22\x18\xf9\xd0\x06\x4d\x89\xa5\x92\xab\ +\x0f\xd8\x1f\x8b\x60\x12\x34\x14\xe2\x23\x4c\x4d\x4e\xe4\x08\xc0\ +\x33\x58\x8c\xf5\xd1\x8a\x87\xc2\x98\x01\x4e\x21\x47\x00\x7a\xf5\ +\xfe\x39\x71\x1f\x2e\x14\xc6\x21\xf1\x74\xec\xca\xd0\x00\x94\x5e\ +\x85\xfe\x47\xbc\xc3\xf3\x2b\x1e\x83\x5d\x18\x12\x00\xf3\x8f\x5b\ +\xe3\x5c\xe0\xcc\x30\xde\x03\xfc\x1d\xcf\xc6\x69\xf4\x0d\x80\x8b\ +\xb3\x43\x71\xae\xf0\x5d\x81\xf7\x31\x2e\xe8\x83\xe8\xca\x71\x1c\ +\x7d\x02\xe0\x74\xfc\x14\x9c\x4b\xb6\x43\xf7\xf7\xe3\x02\x7f\x83\ +\x57\xe3\x96\xd8\x24\x35\x00\xe6\x20\x8f\xc3\xb9\xc0\x49\xd4\xb9\ +\x78\x39\xc6\x8b\x0e\xd7\x05\xee\xfc\x36\x0b\xef\x0b\x0b\x6e\x69\ +\x5d\x84\x07\xa3\x01\x71\xfc\x6e\xde\x37\x4e\x57\x78\xfb\x61\x8c\ +\x1d\xf0\xb5\x98\xb2\x17\x91\x05\x2b\x1f\xbf\x96\x62\xb2\xa4\xc9\ +\xf1\xe8\xfe\x60\x5c\x89\x3e\x86\x64\x4c\x33\xb9\x61\x30\xc2\x5e\ +\xe4\x4c\x5f\xd7\x69\x56\x5e\xaf\xc2\x36\xcc\x15\xd8\x19\xbe\x8c\ +\xf1\xfd\x5d\x74\xb5\x79\x03\xda\xac\xda\x30\x0b\x15\xef\x44\xcf\ +\x24\x08\x6d\x95\xef\xfa\x72\x82\xdf\x98\x59\x1b\xef\xff\x10\xe3\ +\xc2\xeb\xd7\xe8\xbb\x7d\xbe\x6d\xe2\x30\xda\x65\x6d\x31\xd3\x17\ +\xb7\x86\x54\xbe\x0d\x3f\xcf\x57\x5f\xdc\x45\x1e\x92\x55\x9a\x49\ +\x10\x72\x57\x3e\x37\xab\x3d\x08\x66\x8d\x57\x47\xe5\xfd\x8c\x5c\ +\xcb\xe8\x66\x10\x4c\x90\x64\x5b\xa2\xc7\xaf\xca\xe6\xaa\xfc\x21\ +\xf8\x3d\xfa\xea\x5c\xd8\x63\x18\x4a\x33\x08\xbe\x48\x95\x05\xf7\ +\x01\x8d\xe8\xfd\x98\xeb\xb1\x8f\xdf\x2b\xb8\xc4\x0b\x99\x30\x2f\ +\x61\x9e\xe2\xe6\xd1\x4f\x73\x4c\xdc\xa7\x5c\xe1\x85\x12\xd8\xb9\ +\x2d\x34\xcb\x00\xd4\xc7\x85\x65\x19\x80\xfa\xb8\xb0\x2c\x03\x50\ +\x1f\x4b\x60\xda\x2c\x10\x9f\x2f\x0c\x73\xf0\xdf\xe7\x57\x56\xfe\ +\x05\xdb\xb5\xa7\xd2\xe2\x7e\x5c\x73\x00\x00\x00\x00\x49\x45\x4e\ +\x44\xae\x42\x60\x82\ \x00\x00\x1d\x71\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ @@ -1665,516 +1828,10 @@ \xc8\x90\x21\x43\x86\x0c\x19\x32\x64\xc8\x90\x21\x43\x86\x0c\x19\ \x32\xfc\x76\x23\x8a\xfe\x1f\xdf\xac\xfa\xa7\xee\x82\x6f\x5e\x00\ \x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x00\x12\x94\ +\x00\x00\x16\xda\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\ -\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ -\x09\x70\x48\x59\x73\x00\x00\x12\x73\x00\x00\x12\x73\x01\x8c\x22\ -\xb9\x07\x00\x00\x12\x29\x49\x44\x41\x54\x78\x5e\xed\x9d\x0b\x7c\ -\x14\x45\x9e\xc7\xab\x67\x7a\x66\x92\x4c\xde\x6f\x86\xf0\x0c\x04\ -\x79\x0a\x11\xe4\x21\xc8\x43\x5e\xc2\x82\xba\x80\xe0\xb2\xa2\xa7\ -\xe2\xde\xae\x77\xab\xa7\xa2\xb2\xee\xde\x80\xae\xae\x72\x28\x7e\ -\x4e\x94\x45\x56\x3e\xec\x67\x17\x4e\x11\xbc\x8f\x08\x08\xac\x3c\ -\x22\x1e\x2f\x21\x21\x80\x0b\x84\x04\x13\x20\x24\x64\x48\x42\x26\ -\x93\xd7\x64\x1e\x57\xff\xee\xea\x99\xee\x9e\xee\x49\x80\xee\x88\ -\x4c\x7d\xc3\xbf\xab\xea\x5f\x55\x3d\xa1\x7f\xff\xaa\xae\xee\xe9\ -\x99\x20\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x42\xa1\x50\x28\x14\ -\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x72\x9b\xc2\x90\x54\x13\xe6\ -\x6c\xdc\x68\x4c\xfa\xb6\x60\xdc\x85\x8a\x8a\x2c\xe2\x0a\x8b\xc5\ -\x6c\xb8\xf4\xc5\xfa\xfa\x7d\x08\x7d\xe6\x25\x2e\x45\x5e\xb1\xbf\ -\x99\x73\xf2\x6c\xc9\x48\xaf\x57\xda\x2c\x31\x3e\x1e\x1d\xcd\xdb\ -\xfe\x49\x71\x71\x71\x0b\x71\x29\xf2\xfc\x2b\xf6\x9c\xb3\xa5\x97\ -\x42\xfa\xa7\x24\x26\xa2\xc3\x7b\xcf\xe0\xfe\x3b\xc2\xf6\x7f\xe6\ -\x79\x7b\x4e\xe9\xe5\xd0\xfe\x69\x29\x29\xe8\x60\xe9\xf7\x9f\x14\ -\xef\x08\xdf\x1f\xf5\xea\x65\x79\x70\xe4\xc4\x79\xcd\xcd\xcd\xc4\ -\xa1\x8e\xd1\x68\x44\xdd\x6d\x59\x07\x3f\x78\x77\x69\x11\x71\xe9\ -\x8a\xa6\x01\xd0\x6f\xe8\xe8\xad\xa7\x4b\xca\xa7\x33\x4c\x7b\x77\ -\xeb\x47\x49\x71\x31\xa7\xaa\xbb\xa7\x0e\x41\x79\x79\x1e\xe2\x94\ -\x30\x6c\xdc\xd4\xc7\x4e\x17\xfd\xb0\xae\xb1\xb9\x95\x78\xc4\xf8\ -\x91\x89\x31\x54\x75\xe9\xd6\x75\x54\x71\xfe\xde\x12\xe2\x94\xd0\ -\x73\xe0\x88\xc7\x2a\x1c\x35\xeb\x5a\xdc\x4a\xbb\xf7\xa3\x18\xb3\ -\xa9\x2a\xbb\x4f\x8f\xe1\x85\x79\x3b\x4b\x89\x53\x82\xed\x8e\xdc\ -\xc7\x6a\x6b\x5d\xeb\x5a\x5a\x95\xfb\xc7\x5b\xa3\xaa\xc6\x8e\xba\ -\x77\xf8\x17\x9f\xae\x56\xec\x6f\xb1\x74\xc9\xf6\x44\x1b\x0e\xf8\ -\x0d\x86\xf4\xf6\x1e\x6e\x8b\x89\x45\x49\x49\xb1\x8f\x5f\x3e\x93\ -\xff\x57\xe2\xd2\x0d\x23\x49\x6f\x9a\x5f\x2f\x5e\x3a\x76\xc7\xae\ -\xbc\x37\x91\xd9\x82\x90\x01\xef\xb6\x9d\xd6\xd4\xea\x4d\xbf\x33\ -\x36\xce\x75\xa5\xbc\xec\x00\xd9\x95\x04\x53\x4c\xea\xae\xab\xae\ -\x66\xab\x52\x5f\x30\x9f\xd1\x68\x8d\x36\xa2\x4e\xce\xea\xcb\x9f\ -\x91\x2e\x12\x58\x6b\xea\x2e\xa7\xdb\xa3\xda\xdf\x83\x0c\x56\x9f\ -\xab\xc1\xd4\x50\x57\xb5\x9d\x74\x91\x60\xc2\xfd\x5d\xad\x3e\xd5\ -\xfe\x6e\x1f\xb2\x7a\x5d\x75\xa6\x1a\xc7\x25\xc5\xfe\xe6\xe4\xf4\ -\xd5\xad\x26\xcb\xdd\x4a\x7d\xd5\xcc\x83\x03\xc5\xe4\x67\x46\x35\ -\xd5\x55\x2d\x27\xbb\xd1\x0d\x03\x49\x6f\x9a\xe2\xf3\x17\xd2\x99\ -\x1b\xd8\x1d\xcc\x16\xd7\x6a\xea\x1a\x48\x31\x84\xa6\x96\xe6\x46\ -\x92\x55\xa5\xbe\xb1\x49\x71\xf6\x00\x2c\x16\x73\x32\xc9\xaa\x12\ -\x15\x15\xad\xda\xc6\x6c\x36\xb5\xd9\x3f\x3a\x26\x4a\xb5\x8d\xb7\ -\x15\x9f\x36\xfc\x7e\x52\x6a\x3f\xcd\x1e\x1f\x9e\x31\xf4\x47\xb3\ -\x53\xc0\xa4\xb9\x4f\xce\xd9\xbd\x73\xcf\x46\xbf\xd9\x4c\x3c\x3c\ -\xe1\x5e\xc0\x8f\x0f\x4c\xac\xc1\x7b\x71\xd7\xaa\xf9\x4f\x8e\xc8\ -\x8e\xaf\x25\x6e\x09\xf3\x5e\xfd\x72\xd4\xe6\xff\xbb\xf0\xae\xd7\ -\x64\x32\x32\xb2\xbd\x41\x7f\x2b\xeb\x77\xbf\xfe\xab\x09\x0b\x9f\ -\x7b\xa8\xf7\x3f\x89\x5b\xc2\x82\xe5\x05\xbf\xd9\xb0\xf5\xc0\x02\ -\x9f\x4a\xff\x78\xb3\xc1\xfd\x5f\xcf\x4d\x5f\xb8\x70\x72\x27\xc5\ -\xfe\xf3\xdf\x3a\xf2\x9b\x4f\x77\x7c\xa7\xda\x3f\x39\x8a\x75\xaf\ -\x7d\x75\xc2\xcf\x66\x8e\xec\xae\xf8\xfb\xbf\xf4\x97\xe3\xa3\xde\ -\xff\xf4\xd0\xbb\x2d\x7e\x83\x31\xdc\xa9\x51\x1e\x22\xd1\x2c\x8b\ -\x1a\x2f\x7f\x1f\xee\xf0\x69\x82\x66\x2f\xa0\x14\x00\xfd\x92\x8d\ -\xab\x9f\x9b\x3b\xd8\x44\x8a\x21\x18\x8c\x26\x34\x63\x7c\x7f\x47\ -\x5a\xbc\x21\xec\x28\xdf\x7f\xd2\x91\x76\xf6\xdc\xc5\x18\x52\x0c\ -\x62\x60\xd0\xc4\x11\x7d\x1c\xdd\x33\x63\xc2\xf6\xcf\x2b\xac\x4c\ -\x3b\x57\x72\x59\xb1\xff\xe4\x51\x7d\x1c\x5d\xd3\xc3\xf7\xdf\x7b\ -\xbc\x32\xad\xe4\xbc\x52\x7f\x23\x9a\x32\xba\x8f\xa3\x4b\x6a\x54\ -\xd8\xfe\xc7\x4a\x5c\x69\x05\x85\xe7\x70\x7f\xf5\x99\x60\xd1\xc7\ -\xc7\x06\xd5\xb9\xd1\x50\x52\xbc\x3d\x02\xe0\xfe\x9c\xf8\xc5\xdb\ -\x3e\x98\x2b\x9d\x12\x28\x8a\x64\x3e\xb0\x76\x4c\x55\xa3\x77\x22\ -\x29\x76\x58\x00\x68\xb6\x06\xa0\xfc\x34\xa1\x01\x10\xe1\xd0\x00\ -\x88\x70\x68\x00\x44\x38\x34\x00\x22\x1c\x1a\x00\x11\x8e\x66\x01\ -\xd0\xb3\x8b\xcd\x8d\x90\x8f\x94\x30\x3e\x1f\x8a\x4a\x48\x20\x05\ -\x4a\x5b\xc4\x59\xa3\xb9\xbb\xa2\x02\x31\x16\x13\x3e\x9e\xfa\xa3\ -\x59\x00\xac\x5e\xfe\xfa\x17\xbd\x7b\x66\x9d\x66\xb0\xf0\x8c\xdf\ -\x8f\x58\xaf\xe7\xf4\xb2\x67\x27\x1f\x21\xd5\x94\x36\x58\x30\x73\ -\xe8\xe7\x26\x5f\xab\x9b\x41\xf8\xd8\xe1\x81\x94\x14\x1f\xfd\x16\ -\xa9\xd2\x15\x4d\x6f\x34\x7c\xb8\x7e\x7d\xd2\xdf\x3e\xde\x70\x9f\ -\xdb\xd5\x84\x32\x7b\xf5\xd9\xbd\xf5\xe5\xec\x6c\xec\x9e\xc6\xd7\ -\x52\xda\x60\xfb\xb0\x67\xf6\xd6\xa4\xa7\xc6\xcf\xba\x78\xe1\xca\ -\xee\x93\xf9\x7b\xf2\x89\x5f\x57\x74\xbd\xd3\xe4\x2f\x5c\x0e\xb7\ -\x36\x69\x00\xb4\x8f\xed\xcc\x9d\x2f\x1e\x25\xf9\x0e\x83\x2e\x02\ -\x23\x1c\x1a\x00\x11\x0e\x0d\x80\x08\x87\x06\x40\x84\xa3\x79\x00\ -\xd8\xed\xf6\x28\xfb\x8a\x15\x89\xa4\x48\xb9\x4e\xec\xcb\x56\x66\ -\x92\x6c\x87\xa0\xe9\x55\xc0\xe4\x07\x1e\x7e\xe1\xdb\x83\xf9\xcf\ -\x5a\x4c\xa6\x78\xe4\x67\x5e\xaf\xf9\xea\x89\x3c\xec\xa6\x57\x01\ -\xed\xa0\xcc\xd1\xf0\x75\xee\x13\x1b\x5f\x36\x9b\x8c\x33\x5b\x5b\ -\x3d\xa7\x6c\xb6\x4e\xbf\x38\x79\x68\xf7\x49\x52\xad\x1b\x46\x92\ -\xde\x34\xbf\x7f\xfb\xbd\xde\xff\xf3\xd9\x96\x2f\x9b\x91\x31\xa1\ -\xd9\xe7\x8f\x6a\x71\xbb\x27\xb7\xb2\x09\xa7\x26\x0c\x4a\x89\x26\ -\x4d\x28\x61\x98\xbd\x64\xff\xec\x33\x97\xaa\x1f\x70\xb9\xbd\xa8\ -\xc9\xe3\x4f\xf7\xb6\x34\x8f\x6c\xbc\x56\xb5\x9a\x54\xeb\x86\x66\ -\xa7\x80\xa3\xf9\x27\x07\xbb\x5b\x82\x8f\x6e\xfb\x59\x13\x2a\x38\ -\x58\x68\x25\x45\x4a\x1b\x9c\x2a\x2a\xb3\x8a\x1f\x18\x6b\x74\xfb\ -\x06\x93\xac\xae\x68\x16\x00\xfc\x47\x26\xe4\x67\x14\xd1\x7b\x03\ -\x94\x5b\x12\x7a\x15\x10\xe1\xd0\x00\x88\x70\x68\x00\x44\x38\x9a\ -\x05\x40\x82\x35\xae\xd1\x2f\x3e\xe7\xc3\x5b\xc2\xd1\xf4\x02\xa0\ -\xbd\x44\x59\xcc\x78\x09\x15\x5c\x43\x45\x5b\x54\x3f\x4e\xa1\x29\ -\x9a\x05\xc0\xa6\xb5\xef\x6d\x33\x1b\xd8\xe3\x20\x3c\x58\x9c\x85\ -\x69\xfc\xd3\xb3\xf7\x29\x7e\xde\x8f\x12\xca\xcc\x31\x7d\xf7\x98\ -\x84\xa5\xb4\xcf\x87\xdc\x0d\x8d\x7f\xe2\x0a\x3a\xa3\xd9\x7d\x00\ -\x20\x39\xb6\xd3\xfa\x2e\x5d\x32\x2c\xbe\x56\xef\x41\x5b\x66\xea\ -\xbc\x25\x8f\x0e\x80\x29\xa0\x37\x5f\x4b\x09\xc7\xfd\xc3\x6d\x3b\ -\xf7\x9e\x6a\xdd\x7c\xa1\xac\xbc\xaa\x6f\x76\xd7\xbf\x5f\x3a\x77\ -\xec\x6d\x52\xa5\x2b\xf4\x79\x80\x5b\x07\xfa\x3c\x00\xa5\xe3\xa1\ -\x01\x10\xe1\xd0\x00\x88\x70\x68\x00\x44\x38\x9a\x07\xc0\x6f\x17\ -\xbf\x91\x31\xef\xb7\x8b\x33\x48\x91\x72\x9d\x2c\xf8\xf7\x17\xb3\ -\xed\xf6\x95\xb1\xa4\xa8\x3b\x9a\x5e\x05\xe4\x8e\x9e\x6c\x3f\x73\ -\xf6\xfc\x4b\x3e\xbf\x0f\x21\x8f\x6f\x59\x53\xde\xbf\x6d\xc3\x6e\ -\x7a\x15\xd0\x0e\x4e\xfc\x50\xbd\x6f\xc4\x53\x9f\x2e\x61\x59\x76\ -\x3c\xcb\x1a\xaf\x5a\xac\x51\xf7\x57\x9e\x2d\xd0\xfd\xaa\x40\xb3\ -\xfb\x00\xcf\xdb\x97\xdf\xf1\xe5\xf6\x9d\x9b\xdc\x06\xd6\xe4\x65\ -\x8c\x26\xaf\xdf\x3f\xae\xd6\x6d\x3e\x3d\xf5\xae\x4c\x0b\x69\x42\ -\x09\xc3\x2c\xfb\xbe\x39\xa5\x35\x0d\x53\xdc\x7e\x06\x35\x7b\xfd\ -\x31\xac\xdf\x37\xb2\xd9\xe9\x58\x45\xaa\x75\x43\xb3\x53\xc0\xc9\ -\x33\xa7\x07\x7a\xbd\xa2\x77\xb4\x59\x13\x3a\x57\x78\x26\x8a\x94\ -\x28\x6d\x50\x5c\x56\x19\x05\x37\x51\x05\xdc\x5e\x66\x20\xc9\xea\ -\x0a\x5d\x04\x46\x38\x34\x00\x22\x1c\x1a\x00\x11\x8e\x66\x57\x01\ -\xf4\x5b\xc2\x82\xbc\x74\x20\x76\xe9\x5e\xe7\x48\x64\x60\x94\xbf\ -\x16\x0e\xce\xf5\xdc\x47\xc1\xb9\x77\x4e\xe1\x2d\x74\x3f\xf7\x13\ -\x94\x43\x9c\xe7\xf1\xb9\xae\xa2\x77\xe6\xe4\x4c\x1b\x77\x67\x8f\ -\xaf\x88\x4b\x13\x34\x9b\x01\x12\x12\x62\xea\x25\xcf\x03\xf8\x7c\ -\xc8\x6c\x8d\xcc\x67\x42\x0d\x06\x06\x59\x53\x33\xb0\x65\x2a\x5a\ -\x6c\x1a\xa4\xb8\x1e\xd2\x74\x1b\xb6\xce\x28\x36\x3d\x0b\x1b\xa4\ -\xf2\x3c\xb6\x8c\x2c\x64\xb1\xc6\x69\xfb\xd6\x2d\x41\xb3\x00\xd8\ -\xf4\xd1\xfb\x3b\x2c\x26\xd3\x61\x78\x2f\x1b\xa2\x3a\x31\xc6\xe4\ -\x5c\xb9\x68\xfc\x37\xa4\x3a\xa2\x20\x8f\x44\x40\x8e\x2b\x87\x22\ -\xf2\xab\x35\x91\x21\xbe\x42\xd0\x12\x4d\xd7\x00\x19\x31\xad\xe3\ -\xee\xec\x9f\xf3\x9a\x2d\x35\xf5\xb5\x9e\x39\xb6\xae\x9d\xd3\xac\ -\x1d\xf2\x2d\x17\xb7\x24\x20\x18\xbe\xa6\xe7\xd3\x30\x06\x70\x79\ -\xbc\x09\x98\xe0\x13\x99\x4e\x68\x1a\x00\x65\x65\x65\xcd\x05\x79\ -\xdb\xec\xe5\xa7\x0f\xda\x8f\x7d\xfd\x75\x1d\x71\x47\x24\x41\xed\ -\xf8\xb3\xbb\xd4\x18\xac\xb3\xdc\x0f\xdf\x0d\x22\x98\xd8\x1f\x34\ -\x3d\xa0\x57\x01\x3a\xc0\x89\x15\x58\xc3\x49\x17\x73\x01\x24\x5f\ -\x1c\xad\x26\xb1\x5e\xb2\x07\xa1\x01\xf0\x63\x10\x38\xa1\x0b\x29\ -\x04\x03\x98\x5c\x70\x95\xe0\xd1\x10\x1a\x00\x3a\xa0\x76\x1a\xe7\ -\xa7\x7d\xfc\x83\x47\x3f\xef\x93\x4f\xf7\x42\x19\xff\x40\x5b\xa1\ -\x3d\x97\xea\x03\x0d\x80\x8e\x44\x32\xed\x87\x03\xb7\x83\xb6\x5c\ -\x7b\x21\xd5\x07\xcd\x03\xe0\x67\x8f\x3e\xdd\xf5\x17\x0b\xff\xa3\ -\x43\xde\xc8\xb8\x55\xe1\x46\xab\xea\x90\x05\x31\xe5\x95\x6d\x8f\ -\x6f\x98\x55\xa4\x7f\xb2\x4a\x1b\x34\x0d\x80\x1e\x03\x86\x2f\xdb\ -\xb9\x75\xe7\xb9\xcf\xff\x77\xcb\x09\x5b\xf6\x90\x0d\xc4\x1d\x71\ -\x08\x12\x83\x68\x21\x06\xb7\x49\xf0\xe5\x21\x5f\x26\xd3\x3b\x94\ -\x7d\x90\x8a\xda\xc9\x8d\xdb\xb3\xf6\x68\x16\x00\xff\xba\xd8\x3e\ -\xe0\x42\xf9\x95\x45\x1e\x53\x94\xb9\xc5\xc0\xa2\x8a\x5a\xe7\x23\ -\x4f\xaf\x38\x3c\x96\x54\x47\x14\x20\x16\x88\xa6\x88\x64\x36\x87\ -\x82\x7e\xd3\x7b\x7b\xd0\x2c\x00\x4a\xce\x5f\xea\x0b\x91\x1c\x80\ -\x65\x51\x79\x71\x69\xc7\x7c\xbe\xe9\x16\x03\xb4\x67\x54\xde\x07\ -\x08\x10\x52\x2d\x0b\x04\x2e\x8a\xf8\x2c\xd0\xc6\xde\x6e\x18\xba\ -\x08\xd4\x89\x70\x37\x74\x38\xc3\x7a\x73\x29\x9e\x2a\x24\xe5\x40\ -\x3d\xf6\x73\x3e\xbe\x9e\xdf\x68\x0f\x0d\x80\x1f\x0d\xa2\xa8\xea\ -\x0a\x9f\x04\x10\x69\xa6\x93\xfe\x34\x00\xf4\x40\x2c\x9c\x40\x40\ -\xc8\x40\x06\x04\x0e\x38\xf9\x14\x3c\x24\x0f\x5b\x2e\x34\x60\x23\ -\x54\xeb\x00\x0d\x00\x3d\x10\xe9\x2a\xac\xf4\x85\x32\xe0\x83\x15\ -\x3f\x34\x82\x20\x80\x04\x46\x3b\x4e\x7d\x30\xe7\x63\xb8\x76\x78\ -\xc3\xa7\xdc\x3f\xce\xf4\x40\xb3\x00\x48\x4b\x4e\xaa\x95\x7c\x27\ -\x50\x04\xff\xbd\x00\x4e\xdc\x00\x20\xaa\x78\x9a\x67\xf0\xac\x1f\ -\xf4\xf1\x2d\xf9\x2d\xef\x11\xda\x92\x54\xd8\x95\x4e\x11\xa0\x59\ -\x00\x6c\x58\xb5\xfc\xeb\xc4\xf8\xd8\x3c\xe4\xf5\x20\xe4\xf5\xa2\ -\xcc\xc4\xd8\xda\x8f\x5e\x9e\xb8\x8f\x54\x47\x18\x82\x88\xea\x08\ -\x7a\x4a\x45\xe7\xfd\x82\x71\xe8\x78\x17\x10\xd0\xf4\x14\x30\xb0\ -\x47\xea\xc4\x7e\x7d\xb2\x67\x0f\xcf\x1d\xf4\x72\xb7\xc1\xd9\x9d\ -\x53\x12\x58\xd5\xbf\xe9\x7b\xbb\x23\x16\x52\x6a\xc1\xf9\x21\xb4\ -\x4e\x4a\xb8\x3a\xad\xd0\x34\x00\xf2\xf2\xf2\x3c\xdf\x1f\xd8\xb5\ -\xf9\xd0\x3f\x3e\x5f\x76\x68\xd3\xa6\x26\xe2\x8e\x3c\xb8\x93\xb7\ -\x1c\xc1\xc7\x8f\x68\x79\x0b\xe9\x69\x43\x20\xe8\x53\xaa\xd5\x02\ -\xba\x08\xd4\x91\xd0\xb5\x40\xb0\xcc\x5f\xe4\xf1\x6d\xe0\x47\xfe\ -\x87\xa9\x79\x44\x7d\x74\x8a\x00\x1a\x00\x3a\xc0\x3f\xe7\x0b\x90\ -\x6b\xf9\x80\xf1\x65\x1f\xde\x0a\x79\x5e\x64\xc8\xc3\x8f\xb8\xad\ -\xb8\x0f\xe4\xf4\x81\x06\x80\x5e\x84\x2a\x19\x30\x26\xe4\xb6\x1f\ -\x98\x92\x4f\x30\x21\x58\xb4\x87\x06\x80\x0e\x08\x62\x29\x89\x26\ -\xaf\xe3\x47\x3e\x2e\xc1\x3f\xc5\xb5\x83\xbe\xd0\x00\xd0\x09\xb1\ -\xd0\x62\x03\x84\x94\xbf\x6b\x42\x4e\x01\x5c\xc2\x8f\x74\x25\xf3\ -\xc1\x46\x07\xb4\x0d\x00\x63\xca\x84\x38\xdb\x1d\x0d\xa6\xe4\xec\ -\x86\x61\x63\xa7\xae\x24\xde\x08\x04\xd4\x6c\x9b\xf6\xb5\x6a\x7f\ -\xbb\x1b\x41\xb3\x00\x78\xf4\x99\x57\x52\x8c\x09\xf1\xbb\x5c\x1e\ -\x7f\x8c\x87\x65\x63\x8e\x9d\x3c\xfb\xcc\xd2\x8d\x65\xe3\x49\x75\ -\x44\xd1\xd6\xa2\x2d\xa4\x5e\x98\xfa\xe5\xee\xc0\x8f\x7e\x41\xa0\ -\x59\x00\x38\xae\x3a\x26\xf8\x7d\xfe\xc0\xa7\x97\xfc\xac\x19\x1d\ -\xc9\x3b\xa2\xc7\xa7\x99\x6e\x79\x0c\x44\x2d\x10\x4e\xc9\x40\x4e\ -\x3e\xcf\x8b\x1b\x78\x48\x14\xf7\xe3\xde\x3b\xe0\xea\x00\xd8\x11\ -\x59\x00\xe2\x36\x46\x96\x85\x9c\xa6\x68\x16\x58\xb7\xc3\x87\x43\ -\x1f\xd9\x1a\xb5\xb4\xce\x63\xc5\xc7\x9a\x3f\xfc\xb0\xe5\x0f\x10\ -\x39\x4c\xc2\xd1\x12\x6e\xcf\xe2\x06\x7c\x4b\x00\x7c\xf8\xa2\x0d\ -\x0f\xa9\x8a\xfa\x58\x64\xea\x7e\x0f\x0e\x04\xa1\x83\x14\x90\x58\ -\xb8\xee\xe7\x5f\x23\xf8\x4a\x8a\xe0\xfd\x38\x2f\xff\x80\x0c\x75\ -\x15\x25\x75\x4d\xee\x7a\x6e\xed\xc0\xbd\x30\xde\xc0\x6b\x08\xdd\ -\x49\x2a\xd4\x0b\xa3\x1b\xca\x5c\x1e\xff\x72\x2d\x2d\x8d\xe8\xd9\ -\xfb\x07\x96\xfc\xe1\xe1\xdc\xd9\x9c\x0b\x36\x5a\x70\xbb\x7c\x3a\ -\x78\xe8\x67\x7d\x97\x1a\x3a\x0f\xe5\x3e\xe0\xc9\x01\xd3\x33\x97\ -\x15\x1f\x2a\xe1\x88\x03\xb2\xa3\xcf\xa5\x90\xe3\x53\x9e\x60\xfb\ -\x60\xee\x7a\x91\xee\x51\x8a\x7c\xaf\xe2\x32\xc9\xe3\x40\xa9\x77\ -\x54\xa0\x09\x99\x0d\x25\xd3\x86\xa4\x8e\x9c\x96\x9b\xe3\x80\x5a\ -\xcd\x4e\x01\xb7\x0b\x47\xe7\x9c\xb6\xb7\x5e\x3c\x82\x57\xdd\x70\ -\xbb\x06\x8f\x1d\x6e\x36\x00\x83\x71\x24\x98\xb8\x2c\xe4\xc5\x69\ -\x70\x1a\xe7\x8d\x4c\xf1\xd8\x42\xeb\x78\x4f\xa8\x4f\x6e\xe2\x52\ -\xf0\x75\x78\x03\xc4\x3e\x40\x9c\x47\xc8\xe9\xb8\x8c\xc6\xa7\xbb\ -\x24\xe2\x03\x34\x00\x14\x28\x98\x7b\xd6\xee\xbe\xf0\x1d\xbc\xa3\ -\x2d\x22\x78\x30\xd5\xe1\xdb\xf0\x62\x05\x91\x96\xe5\x23\x15\x10\ -\x8f\xd6\x70\xc8\xdb\x8b\x09\xfa\xc4\x7b\x81\x7c\x7d\x75\x05\x1a\ -\x97\xe6\x2a\x9e\x7e\x57\x0f\x89\xf8\x00\x0d\x00\x15\x8e\xe3\x20\ -\x68\x85\x20\xc0\x47\x10\x0e\xa2\x78\x14\x87\x9a\x30\x3e\x85\x69\ -\x5a\xda\x56\x5e\xe6\xdb\xc3\x8f\xdc\x2f\x2e\xcb\x7f\xe4\xf5\xea\ -\x06\x08\x79\xd7\xd5\x4a\x34\x36\xb5\xbe\x78\xc6\xd0\x9e\xa3\xa6\ -\xe5\xda\x24\xe2\x03\x34\x00\xc2\x70\x7c\xde\x59\x7b\xcb\x85\xa3\ -\xc8\xab\x70\x17\x46\x7a\xd3\x2e\x74\x44\xf2\x92\x71\x19\x05\xa0\ -\x3d\x16\x53\xb1\x4e\xdc\x8f\x6f\xa7\xb4\xff\xf0\xf0\xaf\xde\x50\ -\x5d\x89\xc6\xa4\x39\xb1\xf8\xd9\x8a\xe2\x03\xfa\x06\x80\xf1\xa7\ -\x1f\x5f\x85\x73\xcf\xd8\x7d\x97\x8e\x21\xee\x2b\xf0\xe0\xa8\x12\ -\xe3\x24\x11\x95\xa5\x86\xc7\xaa\x70\x6f\x1f\xc0\x29\x27\xb6\xcc\ -\x94\xf6\xc1\x3d\x5a\x0f\x79\xa8\x95\xd5\xb5\x6d\x78\x03\xff\xf0\ -\x3e\x1a\xab\xaf\xa0\xd1\x29\xce\xe2\xc9\xfd\x6d\xf7\xa8\x89\x0f\ -\x70\xbf\x83\x16\x28\x5d\x05\x18\x91\xdf\x03\x4f\x37\x93\xa2\x0c\ -\x06\xc5\x44\x99\xd1\xb0\x3e\xc9\x1f\xfd\xe3\x9d\x19\xeb\x88\x33\ -\x84\x2d\xdf\x96\x26\xfd\x6e\x6d\xe1\x9a\x73\x17\xab\x6c\xf2\x7b\ -\xe5\x06\x1c\x60\xc3\xfa\x76\xfd\x6e\xfd\x92\x99\x4b\xba\x26\x36\ -\xd7\x12\xb7\x84\x2d\xfb\x8a\x93\x16\xad\x3d\xb1\xa6\xb4\xa2\x5a\ -\xd6\x9f\x41\x2c\xee\x3f\xa8\x67\xf2\xb6\x43\xab\x1e\x7a\x83\x38\ -\x43\xd8\xb2\xef\x6c\xd2\x0b\x1f\x9f\x5a\x13\x3f\xf3\xd5\x6e\x8c\ -\xed\xae\xe0\xd5\x41\x00\xd8\x67\x5b\x3e\xa5\x36\x04\xf8\x9d\x02\ -\x97\x8b\x61\xda\x05\xc0\x6d\x02\xcd\x14\x5e\x03\x27\x8d\x35\x95\ -\xe8\x9e\xd4\xfa\x73\x53\x06\x74\x1a\x3d\xeb\x9e\x5e\x55\x7c\xbd\ -\x32\x6d\xbd\x5a\xbb\x51\x0a\x80\x76\xe1\x6d\x45\x83\xfb\xf5\x99\ -\x5d\xb0\xff\xab\xcd\xc4\x23\x21\xbd\xc7\xc0\x3d\x8e\x46\xf7\x78\ -\xee\xff\xa7\x00\xfc\x07\x6c\x71\x31\x6f\x5d\x2a\x29\x58\xcc\x7b\ -\xa4\xc4\x75\xca\xd9\xe3\xf2\x32\xaa\x77\x24\x19\x2c\x40\x4e\x56\ -\xc6\x9b\x67\x0a\xf6\xbf\x4a\x5c\x12\xb2\xfa\x0c\x2b\x2a\xaf\x75\ -\x72\x7f\xf5\x24\xf7\x57\xef\x20\x5f\x66\x2e\x17\x38\xca\x04\x94\ -\xf9\x51\x80\x57\xe7\xa6\xfd\x76\x8a\x0f\x68\x36\x47\x27\xc4\xc2\ -\xf7\x1b\xab\xa8\x14\x06\x86\x35\xa3\x38\x96\x19\x47\x8a\x21\x44\ -\x5b\x63\x55\xc5\xe7\xc0\xa3\xa7\xd2\xe9\xca\x26\xa5\x10\x2c\x51\ -\x31\xe1\x6f\x47\x1b\x0c\xa8\xca\x71\x4d\xf5\xcf\xda\xd4\x37\xb5\ -\x04\xea\xf2\x57\xbf\x80\x8c\x95\xf9\xf8\x74\x20\xbe\x3c\x10\xff\ -\x72\x20\x7e\xdb\xc7\x40\x98\x14\xc3\xb7\x14\x6a\xe5\xa9\x9c\xe0\ -\xbe\x60\xc1\x37\x26\xd5\xd9\x6e\xf1\x01\xcd\x02\xa0\x7f\x56\xe2\ -\x66\xb3\x89\xad\x02\x41\xe0\xa9\xd7\xf6\x18\xde\x20\xd6\xef\x41\ -\x3e\x6b\xc2\x26\xb2\x9b\x10\xae\x55\xd7\xac\xe2\xd6\xbe\xb2\xbe\ -\x42\x7f\xe4\xf1\xa0\xec\x4e\xa9\x3b\x48\xf3\x10\x9c\x75\xd7\x70\ -\x7f\x8c\xac\x6f\xa0\x7f\x6b\x2b\xea\xd5\xbb\xb3\x6a\xff\xe4\xb8\ -\xe8\x1d\xe2\xd7\xcf\xff\xe8\x45\x64\xbc\x52\x80\x5f\x16\xee\x13\ -\xc0\x81\x17\x56\xe6\xbc\xac\xca\x2b\x75\xa1\x8e\x37\xbc\x33\x92\ -\x4a\xfd\xbc\xa9\xed\x07\xca\xa2\xf6\x78\x13\xf4\x33\x9c\xf8\xe3\ -\xd2\x60\xe4\xdb\xda\x2d\x3e\xc0\x1d\x1b\xad\xe8\x37\x62\x72\xaf\ -\x8a\x1f\x4a\xff\xd0\xe4\x67\xb2\x88\x2b\x2c\x71\xd1\x66\x94\x9e\ -\x92\xb8\xec\xfb\xfc\xfd\x3b\x89\x4b\x09\xa6\x73\xf7\x41\xaf\xd7\ -\x34\xb6\x8c\x84\xff\xb0\x18\x13\x9e\x8a\x3b\xa5\x25\x6c\x28\x3a\ -\x71\xe8\x63\xe2\x52\x82\x19\x90\x3b\x76\x5d\xc9\xa5\xca\x2c\x79\ -\x7f\xb3\x91\x45\xdd\xbb\xa4\x6d\x38\x71\x64\x5f\xd8\xfe\x7d\x87\ -\x8c\x5e\x57\x5a\xee\x90\xf4\x1f\xf4\xeb\x77\x27\xb8\xd3\x06\x23\ -\x96\xd5\xf7\xed\x0e\x90\x9c\xbb\x17\x05\xc1\xaa\x08\x83\x9c\xdc\ -\x1d\x3e\x57\xd1\xa4\x7e\x99\x63\xae\x47\x7c\x40\xd3\x00\x88\x34\ -\xee\xfe\xcf\x6d\x7e\x77\x7a\x47\x04\x81\x9a\x50\x82\xf8\x0d\x45\ -\x0f\x0d\xcb\x18\x33\x65\xf0\xf5\x89\x0f\xd0\x00\xb8\x49\xee\xb6\ -\xe3\x20\xc0\x33\x81\xd1\xa8\x16\x04\x62\xf9\x84\x39\x44\x7e\xd8\ -\xd5\x25\x56\x07\x8b\x7f\xb5\x1c\x4d\xb2\x35\x17\x3d\x70\x57\xfa\ -\x0d\x89\x0f\xd0\x00\xd0\x00\x08\x82\x96\x54\xb5\x99\x40\x4d\x5c\ -\xfe\x7c\xce\xd7\x88\xeb\x05\x7f\x38\x69\x60\xe4\x97\xa3\x29\x9d\ -\x9b\x8b\x66\xdc\x84\xf8\xc0\x4f\xff\x4e\xcd\x2d\xc0\x91\xa5\xd3\ -\x19\xb3\xe3\x38\x5e\x18\x2a\x7d\x0e\x46\x2e\x24\xbf\x94\x0b\x8a\ -\x0c\x06\x25\x01\xa1\xbd\xd8\x27\x06\x8b\x5f\x05\xe2\xb7\x14\x4d\ -\xea\x1b\x7b\xef\xcd\x88\x0f\xd0\x00\xd0\x88\xef\x5e\x9b\xce\x98\ -\x1c\x85\x38\x08\xbc\x9c\x74\xea\x26\x88\x2e\xf7\xf3\x41\x01\x06\ -\xf5\x21\xab\x7e\x62\x20\xfe\xd4\xac\xe6\x73\x43\x52\x3c\xe3\x7f\ -\x3e\x6a\xd0\x55\x3c\xe7\x18\xb0\x09\x51\x73\xdd\xd0\x00\xd0\x90\ -\xa3\x38\x08\x58\x12\x04\x6d\x23\xd6\x2c\x18\x14\x52\xa4\x6d\x9c\ -\x55\x97\xb1\xf8\x4d\xc5\xd6\x2b\x05\x53\x9f\x7e\x70\xcc\x35\xec\ -\x84\x47\x84\x40\x43\xe6\x46\x83\xe0\x86\x3a\x51\xc2\x93\xfb\xfb\ -\x6d\x7e\x4f\xc6\x10\xbc\x26\x50\x1b\x5f\x30\x96\xe1\xd0\xcb\x53\ -\x31\xbc\x8f\xdf\xf2\xd3\xfe\xd4\xce\x0d\xe7\x6b\x0f\x6f\x7e\xf0\ -\x93\x35\xef\x55\x62\x77\x2b\x31\x38\xef\x80\x41\x53\x30\xf8\x36\ -\x31\x2e\x6d\x0f\x74\x06\xd0\x81\xc2\x3f\x4e\xbf\x8f\x81\x9b\x45\ -\x5e\xe1\x66\x91\xdc\x78\x61\x83\xa9\x92\xf1\x75\x20\x3f\x77\xce\ -\xcf\xac\x2f\x2d\xdb\xb1\xe6\x11\x2c\xbe\x13\x3b\xe1\xbb\x97\x60\ -\xf4\xc3\xaa\x13\x22\x47\x88\xa2\xeb\x46\x1e\x76\x14\x8d\xc0\xca\ -\x4c\xe8\xf7\xbb\x6d\xbb\x51\x27\x3c\x13\xc8\xde\x3b\x00\xa5\xda\ -\x3e\xf0\xd0\xca\xc0\xad\xf6\x27\x65\x38\xcb\xce\x6f\xfb\x70\xfe\ -\xee\x2f\x37\x5e\xc1\x4e\x18\xed\xf0\x2d\xec\x30\xfa\x5b\x48\x0a\ -\x26\x3c\x12\x44\x67\x80\x5b\x01\x2c\xc2\x9e\x7f\xbe\x39\x7d\xb4\ -\xb7\x1c\xde\x4a\x96\x3c\x5a\xa4\x22\xbe\x58\x33\x5e\xfc\x3a\x2c\ -\xfe\x7d\xe9\x4e\x3c\xf2\x57\x3e\x82\xc5\x57\x9a\xf6\x03\xa2\x03\ -\xd7\x23\xbc\x00\x9d\x01\x74\x06\xcf\x04\x03\xbb\x2d\xda\x55\x10\ -\xdb\x6d\x80\xd1\x60\x68\x6b\xbc\x81\x7e\x20\x09\x5c\xe7\x57\xa0\ -\x89\x19\x75\xe7\xaf\x1d\xfc\xdb\xac\xcd\x7f\xfd\x0b\x5c\xea\x81\ -\xd8\xb0\xba\x04\x03\xf1\x85\xbc\x60\x7e\xbc\xb9\xee\x00\xa0\x33\ -\x80\xfe\xd4\x0d\x36\x5f\x5e\x5c\x5f\x7a\x12\x2f\x09\xda\xd2\x27\ -\x28\xfe\x8c\xae\x4d\x57\x47\x26\x5e\x9b\x8f\xc5\x2f\xc5\x4e\x17\ -\xb6\x06\x6c\x8d\xd8\x9a\xb1\x09\xa7\x00\xb0\x1b\x16\x1f\xa0\x33\ -\x80\xce\xe0\x19\x20\x11\xd2\x87\xdf\xf8\xfc\x97\x87\x6b\xac\x2b\ -\x62\x7b\x0c\x64\x61\x26\x10\xc6\x3a\x07\x29\x40\xe2\x72\x54\xa2\ -\xb9\xbd\xdc\xe8\xed\xf9\x77\x47\x93\x1a\x00\x52\x79\x3e\xe0\xbb\ -\x51\xf1\x01\x1a\x00\x1a\x83\x05\x97\xff\xb5\xd4\x80\x38\xf3\x96\ -\x6f\x7f\xfc\x40\x85\x71\x65\x6c\x8f\x41\x38\x08\xc8\xa1\x27\x4f\ -\x04\x41\x23\x78\x4b\x77\x4e\xcf\x16\xb4\xfc\x97\xc3\x61\x85\xaf\ -\x26\x6a\xc0\x7f\x33\xc2\x0b\xd0\x00\xd0\x18\x1c\x00\xf8\x9f\x04\ -\x89\x48\xf3\xdf\xdb\xf5\xc4\x37\x17\xfd\xab\x62\xbb\x0f\xc4\x17\ -\x07\xfc\x19\x18\x1a\x34\xd4\x54\xa2\x59\xdd\x1a\xd1\xb2\x05\xa3\ -\xb8\x9b\x3a\x5a\x88\xdb\x1e\x68\x00\x68\x0c\x88\x47\xb2\x1c\x4a\ -\x42\x3e\xf6\xdf\x7b\x9e\xfc\xe6\xa2\xf7\xcf\xd6\x2e\xfd\x59\x83\ -\xd1\x88\x1a\xaa\x2b\xd0\x83\x5d\x5c\xe8\x9d\x7f\x19\xdd\xe1\x7a\ -\xd0\x00\xf8\x91\x78\xfc\xfd\xbd\x4f\x7d\x73\xc1\xbb\xca\x6b\x4d\ -\x61\x7f\x9e\x55\x8f\x56\x3c\x75\x2f\xd5\x22\xd2\x58\xf8\x61\xde\ -\x53\x4f\x7c\x90\x77\x9a\x14\x29\x14\x0a\x85\x42\xa1\x50\x28\x14\ -\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x42\xd1\x1e\x84\xfe\x1f\x55\ -\x0b\x04\x29\x5c\xfb\x2b\x5e\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ -\x42\x60\x82\ -\x00\x00\x07\x52\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ -\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ -\x09\x70\x48\x59\x73\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7\x6f\ -\xa8\x64\x00\x00\x06\xe7\x49\x44\x41\x54\x78\x5e\xdd\x9b\xdb\x6f\ -\x14\x55\x1c\xc7\x7f\xe7\xec\xad\xdd\x5e\xd8\x5e\x2c\x5d\x4a\xb7\ -\x2d\x95\x4b\x03\x7d\x90\x82\xc6\x0b\x86\xad\x31\x98\x80\x18\x0c\ -\x60\xf4\xc1\x4b\xe2\x83\x41\x83\x0f\xea\x93\x7f\x82\x1a\x0d\x46\ -\x5f\xd0\x10\x4d\x34\xb1\x9a\xa0\x4d\x6b\xe0\x41\x5a\xc5\x88\x91\ -\xd6\x88\x20\xb4\x29\x6d\x29\xa6\x2c\xad\xb4\x85\x76\x2f\xdd\xcb\ -\xcc\xf1\xfc\x66\xcf\x94\x4e\xbb\xbb\xdd\xcb\xcc\x74\x97\x4f\x02\ -\x7b\xce\xaf\xdb\xb0\x9f\xef\x9c\xdb\x4c\x29\x81\x7b\x84\x89\x4b\ -\x1d\xa5\x55\x84\xbe\x09\x04\x0e\xf3\xee\xe6\x78\x95\x8c\x12\xc2\ -\xce\x10\x60\x27\x68\xcb\xa1\xbe\x78\x4d\xcb\x3d\x11\x80\xfc\xcf\ -\x77\x0d\x32\x81\xd3\x84\x10\x21\x9e\x00\xc6\x3a\x89\x14\x7d\x83\ -\xb6\x3e\xff\xaf\xa8\x28\x14\x7c\x00\x71\x79\xd2\x43\x08\x34\x89\ -\x52\x52\x18\xb0\x29\xfe\xe7\xa0\xad\xe5\x50\xaf\x28\x01\x15\xaf\ -\x05\x49\x26\xf2\x08\x01\x52\x35\x31\xe5\x3f\x75\xbe\xfb\xe3\x27\ -\x45\xa9\x70\x03\xc8\x54\x1e\xf1\x4d\xcd\x82\x6f\x7a\xce\x01\x12\ -\xeb\x18\xf9\xe9\xb3\x06\xac\x15\x64\x00\x39\xc8\x2b\xed\xea\x35\ -\x25\x2e\x4f\xad\xeb\x43\x6c\x17\xdc\x1a\xa0\x83\x3c\x78\x6a\x5c\ -\x4a\x3b\xc6\xa0\xcd\xa2\xb4\x0a\x04\x3d\xe5\x11\x4a\x20\x5a\x30\ -\x01\x04\xb9\x3c\xd5\x51\x5e\x50\x52\x10\x53\x00\xe5\xed\xfa\xcb\ -\xf3\xa3\x01\x0b\xe6\xfd\x22\x68\x94\xbc\x02\x3f\x22\xe6\x75\x00\ -\x86\xca\xc7\x19\xcc\xdb\x00\x4c\x90\xe7\x73\x80\x74\xe4\xe5\x1a\ -\x60\x86\x3c\x63\xfc\xea\x57\x94\xb6\xe5\xdd\x08\x30\x49\x7e\x94\ -\x32\xb6\x87\xba\xf7\x04\xf2\x2a\x80\xb8\x3c\x98\x21\xef\xa5\x5b\ -\x0f\x8e\x61\x3f\x6f\x02\x60\xc3\x9d\x9e\xb8\x3c\x31\x4d\x1e\xc9\ -\x8b\x35\x00\xe5\xa5\x70\xa4\xd7\x6c\x79\x64\xd5\x03\x58\x4d\x79\ -\x64\x55\x03\x58\x6d\x79\x64\xd5\x02\x60\x7d\x1d\x9e\xc0\xe0\x50\ -\x6f\x6c\xec\x46\x93\x74\xc7\x0f\xc4\x6e\x05\xeb\xda\x6a\x70\x6c\ -\x69\x04\x6b\x5d\x8d\x78\x97\x16\x8d\x7c\x39\x97\x5f\xbb\xb2\x7c\ -\x84\xcb\x3b\x93\xc8\x23\xab\x12\x80\xef\xd5\xa7\x9b\x88\x3f\xfc\ -\x93\xec\x0f\x26\xbc\xf2\xb6\x06\x37\x94\xed\x7b\x1c\x6c\x8d\xeb\ -\x44\xc5\x18\x79\xc4\xf4\xbb\xc1\x9b\x2f\xec\xdd\xc0\xa6\x67\x7f\ -\x66\x91\x88\xf2\x44\x26\x11\x32\x1f\x11\xa1\xbe\xcb\x00\xd1\x18\ -\xd8\xef\xaf\x57\xc4\x8d\x90\x47\x4c\x0d\x00\xe5\xe5\xb9\xb9\x5e\ -\x60\x72\xbd\x28\xa5\x24\x7a\xed\x06\xf8\x7d\xb7\xc0\x57\x55\xc9\ -\xc7\x2a\xd1\x5d\x1e\x31\x2d\x00\xe5\xca\xfb\xe7\x7a\xb8\xbc\x47\ -\x94\xd2\x82\x4c\x4e\x03\x91\x19\x94\xb5\x6c\x48\x43\x9e\x71\x79\ -\x48\x5b\x1e\x31\xe5\x20\xa4\xca\x33\x39\x33\x79\x95\xb2\x0b\x03\ -\x50\x1b\x0c\x88\x5e\x62\xb2\x91\x47\x0c\x1f\x01\xb9\xca\xab\x48\ -\x7c\x24\x14\x3f\xb8\x4d\xf4\xb4\xa0\xbc\xc5\x61\xdf\x6d\xdf\x7c\ -\xe0\xba\x28\xa5\x8d\xa1\x23\x40\x2f\x79\x24\x3a\xe6\x83\xd8\xf8\ -\xa4\xe8\xdd\x45\x95\x27\xcd\xfb\x33\x96\x47\x0c\x0b\x40\x4f\x79\ -\x95\xf0\xc0\x35\xd1\x8a\x93\xab\x3c\x62\xc8\x14\x40\x79\x3e\x68\ -\x7b\x6c\x9e\x5a\x8f\x6d\x5d\x0d\xd0\x92\x62\x90\x43\x61\x5e\x92\ -\xc4\x3b\xb2\x83\x96\x39\xa1\xa8\x75\xa3\xd2\xd6\x43\x1e\xd1\xfd\ -\x20\x14\x3a\x7d\xac\x89\xc4\x58\x2f\x3f\xc4\x78\x80\x2e\x1a\x60\ -\x92\xcc\xaf\xe0\x28\x04\x7a\xfb\x94\xed\x2d\x1b\x1c\x5b\x9b\xc1\ -\xf5\xf2\x7e\x6c\x8e\x50\xbb\xcd\x9b\xab\x3c\xa2\xeb\x08\x60\x97\ -\x3a\x3c\x64\x4d\x79\x8f\xa5\x72\x4d\x23\xee\xdb\x1a\x28\x01\x6b\ -\x4d\xa5\xb2\x90\xf1\xaf\x43\xe4\x2a\xff\xec\x3c\x94\x4c\x70\x6c\ -\xf4\x80\xa3\xa5\x69\x84\x4a\x92\x97\x6c\x79\x36\x67\x79\x44\xb7\ -\x00\x50\x5e\xa2\x96\x1e\x42\x09\x1f\xfe\xa9\xb1\xad\xbb\x8f\x9f\ -\xf9\x9b\x20\x74\x71\x48\x39\xed\xa5\x8b\x73\xd7\xf6\x11\x7b\x4d\ -\x85\x97\x6c\x3b\xac\x8b\x3c\xa2\xcb\x22\xb8\x20\x4f\x60\x45\x79\ -\x95\xff\x1c\x0e\x98\x7c\x6a\x17\x30\x9b\x55\x54\x52\x43\x4b\x9d\ -\xa3\xce\x4d\xeb\x75\x95\x47\x72\x0e\x20\x1b\x79\xf5\xc6\x26\x5a\ -\xe5\x82\x68\xfb\x43\xa2\x9a\x1c\x42\xe9\x75\x66\x75\x3c\x41\x76\ -\xbc\xa4\xab\x3c\x92\xd3\x14\xc8\x45\x1e\xa9\xc2\xb3\x7d\x6b\x33\ -\x44\x86\xae\x83\x7c\x3b\x5e\x5b\x0a\xca\x93\xd2\x32\xaf\xfb\xab\ -\xae\x51\x51\xd2\x95\xac\x03\xd0\x43\xbe\x01\xcf\xf6\x7c\xad\xc4\ -\x6d\x72\xfe\xaf\x41\xa5\xbe\x18\x55\xbe\xf6\xeb\xee\x11\x51\xd2\ -\x9d\xac\xa6\x80\x6e\xf2\x02\x5c\x10\x89\xc3\x2e\x7a\x71\x18\xbf\ -\x2b\xb6\xd8\xac\xaf\x19\x29\x8f\x64\x1c\x80\xde\xf2\x0a\x16\xaa\ -\xec\x0c\x2a\x28\x8f\xaf\xb1\x70\xf8\xf3\xf1\x7d\x0f\x6f\x51\x8a\ -\x06\x91\x51\x00\xc1\x9c\xe5\x9d\xcb\xe5\x05\x7c\x95\x57\x5e\x55\ -\x79\x9c\x19\xfc\x6f\x37\x01\x7a\xc6\xc8\x10\xd2\x0e\x00\xe5\xed\ -\x39\xcb\x57\x28\xed\x44\xc8\xe1\xc8\x12\x79\x15\x63\x43\x48\x2b\ -\x00\xa3\xe5\x41\x96\x21\x3a\x3e\x99\x40\x5e\xc5\xb8\x10\x56\x0c\ -\xc0\x70\x79\xce\xfc\xc5\xab\x12\x0b\x84\x58\x62\x79\x15\x63\x42\ -\x48\x19\x80\x19\xf2\xb1\xa9\xdb\xb1\xd9\xef\xcf\x60\x33\x8d\x2d\ -\x59\xff\x10\x92\x06\x60\x96\xfc\xf4\xa7\xdf\x02\xf3\x87\x32\x38\ -\x8f\xe8\x1b\x42\xc2\x00\xcc\x90\x67\x0c\x46\x66\xbe\xe8\x3a\xce\ -\x66\xfd\xe9\xdd\x0c\x68\xd0\x2f\x84\x65\x01\x98\x25\x1f\x91\x25\ -\x6f\xed\xf1\x93\x47\xf8\xca\xff\x81\x28\x67\x88\x3e\x21\xf0\x75\ -\xe7\x2e\x66\xca\x3b\x17\xdd\xd5\x8d\xef\x7b\xec\x7d\xfe\x41\xde\ -\x12\xdd\x0c\x61\x3e\x06\x72\x7b\x5d\xd7\xb9\x01\x51\xc8\x88\x85\ -\x00\xe4\xa1\x93\xf5\xb7\xef\x04\x7a\x83\xe1\xd8\x86\x68\x4c\xe2\ -\x87\x33\x02\xc5\x0e\x1b\x94\x3b\x8b\xc0\xca\x4f\x6a\x89\xd0\x43\ -\x5e\x65\xa5\x10\xf8\xf7\xbe\x0b\x84\x2c\x7f\x2a\xca\xa1\x32\xf8\ -\xdc\x3f\x9e\xed\x16\xdd\x8c\x50\x02\xe8\xeb\xfc\xc8\x63\xb5\x5a\ -\x7b\xa2\x31\x79\xd9\x95\x27\x7c\x38\x54\x96\x15\x83\xbb\xaa\x1c\ -\xec\xd6\xbb\x6b\x95\x9e\xf2\x2a\xa9\x42\x90\x18\xdd\x54\xdf\xfd\ -\xcb\x90\xe8\xea\x06\x3d\xfd\xe5\x7b\x25\x32\x23\xa7\x12\xc9\x23\ -\x8c\x7f\xf2\xa9\xd9\x20\x5c\x19\x9b\x80\x99\xb9\x90\x52\xcb\x46\ -\x9e\xda\xe8\xee\x54\xf2\x48\x5d\xd7\xaf\x6f\x67\xbf\x26\x64\x07\ -\xad\xa8\xb0\x1f\xe5\x57\xb9\x45\xf4\x93\x22\xc9\x0c\x46\x6f\x4e\ -\xc3\xf0\x8d\xa9\xac\xe4\xe9\xc6\x03\x9a\xdf\xd4\x48\x86\xd9\x21\ -\x50\x7e\xfa\x7e\x4e\xb4\x15\x94\x2b\x3e\x33\x07\x81\xe0\xbc\xa8\ -\x68\xb9\x13\x98\x57\xa6\x85\x11\xf2\x2a\x66\x86\x40\xb9\x8c\xe6\ -\xf7\x6c\x06\x86\xc7\xe1\x5c\xff\x00\xf4\xfc\x76\x11\x7e\xef\x1f\ -\x4c\x1a\x04\xae\x09\x2b\x30\x9c\x8d\xbc\x8a\x59\x21\x50\x7e\x95\ -\x16\x76\x02\x24\xcc\xef\xca\x54\x6e\xcd\xcc\xc2\xd9\x3f\x2e\x2b\ -\x23\x62\x31\x38\x4a\x70\x1d\x48\xc1\x30\xb1\x52\x6f\xb6\xf2\x2a\ -\x66\x84\xc0\xf7\x37\xa6\x79\xd6\x56\x53\xad\xbd\x5f\x8f\xf1\x2d\ -\xf1\xfc\x85\xa1\x65\x23\x61\x9a\x2f\x88\xb1\xc4\xcf\xf5\x75\x91\ -\x57\x31\x3a\x04\x9c\x02\x3d\xa2\xad\xe0\xae\xa9\x84\x0a\x57\xa9\ -\xe8\xc5\xc1\x10\xfe\xbe\xa2\xfd\xa9\x33\x8e\x82\xd9\xe5\xd3\x43\ -\x57\x79\x15\x0c\x61\xe2\x66\x40\xfb\x83\x41\x9d\xa0\x16\xb0\x9c\ -\x10\x6d\x05\xbe\xbe\x41\x5b\x6b\x33\x14\x17\x69\x9f\xd1\x4d\xf1\ -\xe9\xb0\x74\x14\x84\xc2\x51\xd1\x52\x30\x44\x5e\x65\x47\x7f\xbf\ -\xe6\x1f\xd3\x0b\xba\x7d\xff\xeb\xe7\xf9\xd5\xd4\x9c\xa2\x8a\x1c\ -\x76\x78\x74\x67\xcb\xb2\x91\x30\xaf\x15\x56\xb6\x46\x84\x01\x33\ -\x54\xde\x48\x94\x33\x2e\x25\xec\x08\x7f\x99\xc6\xb6\x0a\x86\xf0\ -\x48\x5b\x8b\x32\x1a\xd6\xbb\xab\xa1\xb9\xd1\x0d\x95\x4b\x02\xb1\ -\xf1\x93\x21\xca\x53\xab\xa5\x20\xe5\x91\x85\x1d\xa0\xef\x87\x63\ -\xed\x8c\x00\x8e\x84\xa2\x78\x65\x65\x9a\xeb\xaa\x86\x5d\xe5\xce\ -\x82\x95\x47\x16\xee\x72\x76\x3c\x73\xf4\x0c\x61\xb0\x97\x37\x35\ -\x23\x21\x19\x76\x9b\x65\xd8\x65\x2f\x6c\x79\x44\x73\x9b\xa7\x84\ -\x00\xf2\x03\x4b\xd7\x84\xa5\xf0\xaf\x5f\x89\x46\xa3\xed\xb4\xb5\ -\xb0\xe5\x11\xcd\x21\x68\x31\x7f\x76\x7e\xb2\x53\x02\xe9\x15\x2e\ -\xeb\xe5\x6f\x6b\xe2\xbb\x03\x6f\xb2\x41\x1e\xd9\x37\x33\x33\x91\ -\x63\x7b\x5e\x7c\x27\xf5\x7f\xdb\x2a\x08\x00\xfe\x07\x67\xd1\x50\ -\x78\x73\x48\xdf\xa1\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\ -\x82\ -\x00\x00\x05\x36\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ -\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ -\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ -\x09\x70\x48\x59\x73\x00\x00\x16\xb7\x00\x00\x16\xb7\x01\x5a\x8b\ -\x7b\x20\x00\x00\x04\xcb\x49\x44\x41\x54\x78\x5e\xed\x9b\x59\xc8\ -\x75\x53\x18\x80\x3f\xf3\x4c\x64\xce\x10\x91\x39\xe5\x02\x17\x08\ -\x45\x11\x32\x24\xdc\x28\x12\x19\xae\x64\x2a\x53\x29\x37\x4a\x21\ -\x43\xe6\x12\x17\x72\x27\x94\xbf\x50\x8a\xa4\x94\x79\x0c\x91\x21\ -\x43\xc6\xcc\xe3\xf3\x9c\xbd\x97\x56\xbb\x7d\xce\xd9\x6b\xef\xf5\ -\x9f\x75\x74\xce\x53\x4f\x7b\x7f\xfb\xdf\xdf\xf9\xd6\x7a\xcf\x5e\ -\xd3\xbb\xf6\xbf\x52\x90\x03\xf0\x13\x7c\x0b\x77\xf0\xc2\xa2\x71\ -\x1b\xfe\x53\x7b\xb1\x17\x4a\xb0\x66\x7d\x2c\xc1\xba\xf5\x51\xe2\ -\xf3\x99\x52\x32\x00\x73\xc1\x32\x00\xf5\x71\x61\x59\x06\xa0\x3e\ -\x2e\x2c\x29\x01\xd8\x14\xff\x2f\x01\xdb\x0c\xd7\xa8\x4e\x27\xd3\ -\xb5\x42\x97\xe2\x77\xf8\x2a\x6e\xef\x85\x0c\x7c\x59\x1f\x25\x3e\ -\x1f\x82\xf5\xb9\x1d\x2d\xeb\x73\xb8\x36\x66\xe1\x05\x0c\x93\x96\ -\x77\x30\x47\x10\xfc\x96\x6e\xc2\xeb\x70\x1d\x2f\x0c\xc4\xca\xdf\ -\x8d\xa1\x9c\xba\x33\x66\xe1\x4c\xfc\x1b\x73\x07\x21\x17\x6d\x95\ -\x7f\x14\x3b\x35\x83\xae\x9c\x87\xf3\x18\x84\xb6\xca\x3f\x8e\xeb\ -\xe1\x54\x52\x23\x64\x10\xee\xc0\xf0\x7b\xef\xe2\x11\xf8\xd9\xe8\ -\xa7\xe9\xf8\x7b\xbb\xe3\xde\xb8\x0b\xda\x0c\x6c\xa7\x3f\xe2\xe7\ -\xf8\x36\xbe\x82\xbf\x61\x17\xac\xfc\x9d\x78\xce\xe8\xa7\x8a\x27\ -\xf0\x64\xec\xfa\x19\xc9\xb4\x3d\x09\xdb\xe2\x38\xac\xf4\x91\x78\ -\x1f\x1a\xa8\xf8\x9b\x6a\xf3\x67\x7c\x12\xcf\xc2\x4d\x70\x1c\x7e\ -\xee\x5d\x18\xff\x6e\xe7\x6f\x7e\x28\xcd\x20\xdc\x88\x6d\x9c\x8a\ -\x8e\x1c\x71\x21\x53\xfc\x16\xed\x24\x1d\x82\x9b\x1c\x84\xf1\xbd\ -\x33\xab\x7c\xc0\x20\xfc\x85\xfe\xf1\x0b\xbc\x10\xb1\x2b\x3e\x85\ -\x71\x01\x83\x3e\xee\xcf\xe3\x03\xf8\x50\x7d\x6d\x9a\x9f\xe2\x49\ -\x18\xb3\x13\xfa\xb4\xf8\xef\x33\xaf\x7c\xc0\xa4\x86\x7d\x40\xcc\ -\x89\xe8\x38\x1c\x57\xe0\x27\xbc\x07\xbd\x37\x5e\xfa\xee\x8b\xf1\ -\x7d\xd3\xbc\x15\xe3\xb1\x7d\x37\x3c\x16\x73\x0c\xa3\x59\x38\x1f\ -\xc3\x53\xa1\x7f\xe2\x2d\xb8\x0d\xb6\x91\x1a\x00\x7d\x0c\x37\xc0\ -\xb9\xc3\x4e\x2b\xee\x17\x3e\xc0\x03\x71\x12\x7d\x02\xa0\x8e\xf1\ -\xd9\x66\x79\x39\x38\x0c\xff\xc0\x50\x40\xdb\xf8\x16\x38\x8d\xbe\ -\x01\x50\x67\x91\x73\xc1\xe6\x68\x72\x33\x14\xec\x45\xdc\x18\xbb\ -\x30\x24\x00\x3e\x6d\x27\x60\x71\x9c\x18\x85\x42\xd9\x5b\x8f\x6b\ -\xef\x6d\x0c\x09\x80\x7e\x8c\x1b\x61\x31\xf6\x40\x3b\xba\x50\xa0\ -\xa3\x30\x85\xa1\x01\xd0\x2b\xb1\x18\xce\xee\x42\x41\x1e\xf1\x42\ -\x22\x39\x02\xf0\x15\x16\x19\x15\x9c\xa6\x3a\xbe\x5b\x08\xdb\xa3\ -\x95\x49\x25\x47\x00\xf4\x0c\xec\x85\x8b\x89\xbe\xd8\x01\x6d\x58\ -\x9d\xae\x3c\x8b\xaf\x57\xa7\x45\x38\xad\x3e\x26\x33\x24\x00\x2e\ -\x70\x02\x0f\xd7\xc7\x52\x1c\x8e\xbd\xe6\x05\x43\x02\xe0\x62\x24\ -\xf0\x74\x7d\x2c\x85\xcb\xea\x3d\xab\xd3\x34\xfa\x06\x60\x2d\x74\ -\x1e\x2e\x2e\x48\xde\xab\x4e\x8b\xe2\x88\x94\x8c\x6b\xea\x7d\xf0\ -\x7a\x9c\xb4\xf6\xfe\x05\x5d\x96\x3a\xc9\x91\xad\x30\x24\x32\x4d\ -\x62\xec\x55\x9d\x26\x63\x27\xf8\x5a\x75\x3a\x98\x0b\xd1\x84\xa8\ -\x38\x05\xbf\x06\x27\x8d\x0e\xae\x4a\x47\x43\xe8\x2a\x6c\xeb\x59\ -\x9b\xbe\x84\x01\xb3\x39\xe1\x7a\x08\x4a\x1f\x72\x8d\x02\x7a\x19\ -\x06\x2c\x6b\xdb\x3d\x4d\x57\xd9\x04\xdc\x9f\xef\x42\x7c\x9f\xf3\ -\xfe\x40\xb1\x9d\xdd\x06\x71\x99\x3a\xd7\xc9\x26\x60\x10\x8e\xc6\ -\x49\x4d\xc0\x76\xee\x93\x12\xfe\x88\xf7\xfe\x50\x9d\x8e\xd6\x01\ -\x3b\x56\xa7\xc9\xe4\x6c\x02\xe6\x05\xef\xad\x4e\x47\xf9\x01\xeb\ -\x14\x86\xe9\x36\x6c\x02\xd6\xa9\x37\xf6\x01\x3e\x46\x4e\x82\xba\ -\x2e\x7e\x9a\xe4\x6c\x02\xcd\xc4\x4c\x27\x86\x0c\x83\x6f\xd4\x47\ -\x9f\xa2\x78\x48\x2c\xc5\x9b\xf5\x31\x89\x21\x01\x70\xf6\x17\x30\ -\x2d\x55\x12\x47\xa2\x2f\xaa\xd3\x34\x86\x04\xc0\xfc\x7b\xc0\xb9\ -\x78\xc9\xbc\x9c\x49\xd1\x22\x18\xf9\xd0\x06\x4d\x89\xa5\x92\xab\ -\x0f\xd8\x1f\x8b\x60\x12\x34\x14\xe2\x23\x4c\x4d\x4e\xe4\x08\xc0\ -\x33\x58\x8c\xf5\xd1\x8a\x87\xc2\x98\x01\x4e\x21\x47\x00\x7a\xf5\ -\xfe\x39\x71\x1f\x2e\x14\xc6\x21\xf1\x74\xec\xca\xd0\x00\x94\x5e\ -\x85\xfe\x47\xbc\xc3\xf3\x2b\x1e\x83\x5d\x18\x12\x00\xf3\x8f\x5b\ -\xe3\x5c\xe0\xcc\x30\xde\x03\xfc\x1d\xcf\xc6\x69\xf4\x0d\x80\x8b\ -\xb3\x43\x71\xae\xf0\x5d\x81\xf7\x31\x2e\xe8\x83\xe8\xca\x71\x1c\ -\x7d\x02\xe0\x74\xfc\x14\x9c\x4b\xb6\x43\xf7\xf7\xe3\x02\x7f\x83\ -\x57\xe3\x96\xd8\x24\x35\x00\xe6\x20\x8f\xc3\xb9\xc0\x49\xd4\xb9\ -\x78\x39\xc6\x8b\x0e\xd7\x05\xee\xfc\x36\x0b\xef\x0b\x0b\x6e\x69\ -\x5d\x84\x07\xa3\x01\x71\xfc\x6e\xde\x37\x4e\x57\x78\xfb\x61\x8c\ -\x1d\xf0\xb5\x98\xb2\x17\x91\x05\x2b\x1f\xbf\x96\x62\xb2\xa4\xc9\ -\xf1\xe8\xfe\x60\x5c\x89\x3e\x86\x64\x4c\x33\xb9\x61\x30\xc2\x5e\ -\xe4\x4c\x5f\xd7\x69\x56\x5e\xaf\xc2\x36\xcc\x15\xd8\x19\xbe\x8c\ -\xf1\xfd\x5d\x74\xb5\x79\x03\xda\xac\xda\x30\x0b\x15\xef\x44\xcf\ -\x24\x08\x6d\x95\xef\xfa\x72\x82\xdf\x98\x59\x1b\xef\xff\x10\xe3\ -\xc2\xeb\xd7\xe8\xbb\x7d\xbe\x6d\xe2\x30\xda\x65\x6d\x31\xd3\x17\ -\xb7\x86\x54\xbe\x0d\x3f\xcf\x57\x5f\xdc\x45\x1e\x92\x55\x9a\x49\ -\x10\x72\x57\x3e\x37\xab\x3d\x08\x66\x8d\x57\x47\xe5\xfd\x8c\x5c\ -\xcb\xe8\x66\x10\x4c\x90\x64\x5b\xa2\xc7\xaf\xca\xe6\xaa\xfc\x21\ -\xf8\x3d\xfa\xea\x5c\xd8\x63\x18\x4a\x33\x08\xbe\x48\x95\x05\xf7\ -\x01\x8d\xe8\xfd\x98\xeb\xb1\x8f\xdf\x2b\xb8\xc4\x0b\x99\x30\x2f\ -\x61\x9e\xe2\xe6\xd1\x4f\x73\x4c\xdc\xa7\x5c\xe1\x85\x12\xd8\xb9\ -\x2d\x34\xcb\x00\xd4\xc7\x85\x65\x19\x80\xfa\xb8\xb0\x2c\x03\x50\ -\x1f\x4b\x60\xda\x2c\x10\x9f\x2f\x0c\x73\xf0\xdf\xe7\x57\x56\xfe\ -\x05\xdb\xb5\xa7\xd2\xe2\x7e\x5c\x73\x00\x00\x00\x00\x49\x45\x4e\ -\x44\xae\x42\x60\x82\ -\x00\x00\x16\xda\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ \x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ \x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ \x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\ @@ -2539,6 +2196,1467 @@ \xe6\x82\xc2\xea\xa9\x94\x57\x04\x10\xa0\x24\x18\x65\xc5\x7f\xa5\ \x4b\x47\x8c\xfd\x2f\x03\x29\x07\x44\x48\xb3\xa2\x64\x00\x00\x00\ \x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +\x00\x00\x21\xa6\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\ +\x9c\x18\x00\x00\x21\x3b\x49\x44\x41\x54\x78\x5e\xed\x5d\x09\x9c\ +\x14\xc5\xd5\x7f\xbb\x2c\x7b\x2f\x02\x2b\xb2\x80\x20\x88\x28\x8a\ +\x0a\x78\x1f\x31\x46\x41\xf0\xc2\x1b\x09\x78\x47\x8d\x89\xfa\x79\ +\xdf\xdf\xcf\x23\x44\xcd\xa1\xe6\x82\x78\x25\x26\x2a\x31\x0a\x2a\ +\x9e\x88\x31\x82\x28\x88\x80\x8a\x18\x45\x40\xce\x95\x73\x61\x59\ +\x96\x95\xbd\xaf\xef\xfd\x5f\x55\x75\xd7\xf4\xf4\xcc\xce\x76\xef\ +\x2e\xf9\x7e\x33\xff\x9e\xea\x7a\xf5\xea\x55\x57\xf5\x7b\xaf\xeb\ +\xe8\x99\xe9\x4e\x6b\x6e\x6e\xa6\x14\x92\x17\xe9\x3a\x4e\x21\x49\ +\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x72\xa4\x1c\x20\ +\xc9\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x72\xa4\x1c\ +\x20\xc9\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x72\xa4\ +\x1c\x20\xc9\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x72\ +\xa4\x1c\x20\xc9\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\ +\x72\xb4\xc9\x8f\x42\xab\xaa\xaa\xa8\xb8\xb8\x98\xea\x6a\x6b\xe9\ +\xfb\x8a\x0a\xda\xb1\x63\x07\x87\xb2\x1e\xe5\xe5\x3b\x7e\xb8\x75\ +\xeb\xb6\x13\xb7\x96\x6c\x19\x58\x57\x5b\xd7\xb7\xba\xa6\x3a\x2f\ +\x3d\x2d\xbd\x99\xd2\xb8\x50\x5a\x9a\xf2\xbe\x34\xe5\x83\x69\xe9\ +\x69\xcc\x46\x06\xb2\x34\x85\x98\x09\x49\xe1\x83\x04\x52\x8a\xa9\ +\xf9\x4a\x36\x52\x46\xc5\xde\xe3\x28\x29\x25\xe7\x0b\x56\x45\x33\ +\x76\xd8\x4b\xa4\x53\x88\xb5\x9e\x24\x96\x8f\xca\x53\x32\x9a\x27\ +\x32\x5a\x56\x3e\xa0\x8d\x8c\x4a\xcb\xc7\x2a\x43\xcd\x4d\xd4\xc4\ +\x91\x08\xf2\xa7\xa9\xa9\x29\x2d\x3b\x3b\xab\xa6\x73\x66\xe6\x86\ +\x3d\xf7\xec\xb1\xb6\x5b\xf7\x6e\x1f\xf7\xed\xdb\x6f\x4e\xd7\x6e\ +\xdd\xd7\x17\xe4\xe7\x53\x7e\x41\xbe\x88\x0e\xda\x7f\x10\x15\x14\ +\x74\x41\xc9\x50\x68\x33\x07\xf8\xee\xbb\xef\x44\xc9\x6b\x57\xaf\ +\xe9\x3b\xeb\xfd\xf7\x6e\xfc\x76\xc5\x8a\x09\x3b\x77\xee\xec\xd5\ +\xd8\xd4\x44\x19\x9d\x3a\x89\x31\x3a\xa5\x77\x12\x63\xc0\x00\xe9\ +\xca\x22\x9c\x64\x07\x00\x8b\xd3\xb2\x81\x2d\xb4\x95\x17\xc1\x07\ +\x2d\x4c\x15\xeb\x34\x28\xc9\x77\x64\xec\xb4\x4b\x2b\x52\xc5\x5e\ +\xd8\x86\x73\x8c\x26\x3c\xa6\x35\xdf\x49\x9b\x3c\x87\xa7\xd2\x92\ +\x83\x58\x58\x86\xdf\x84\x28\x82\x6f\x97\x01\xd1\xa4\xd3\x42\xb3\ +\xce\x10\x1a\x1b\x1b\xa5\xad\xf9\xf9\xf9\xe5\x03\xf7\x1b\x34\xfd\ +\xe4\x91\x23\x1f\x3b\xe0\x80\x03\xbe\xa9\xa9\xa9\xa5\xfd\x06\xed\ +\xf7\xdf\xe3\x00\x35\x35\x35\xb4\x69\xd3\x26\xfa\xf0\x83\xd9\x57\ +\x4c\x7f\xf5\x95\x87\xcb\xca\xca\x8a\x32\x3b\x77\xa6\x8c\x8c\x0c\ +\xa5\x78\x96\x11\x43\x88\xe2\x39\xf0\x47\x39\x80\xe6\xe1\x23\x72\ +\x48\x8b\x30\x58\x1c\x79\x1d\x20\x5d\xf3\x85\xa9\x62\x26\xe4\x58\ +\x2a\x03\x92\x6a\x93\xa2\x22\xa4\xca\x22\x25\xb4\x24\x90\x13\x01\ +\xa3\x05\x31\xa2\x18\x43\xcc\xa7\x63\xf0\x74\x1e\xb8\x92\xe0\xab\ +\x15\xb1\xe4\xa9\xb4\xca\x07\x8b\x0d\x2e\x2c\x9b\x2f\x84\xc3\xb7\ +\xcb\x08\x47\xe7\xb9\x34\x07\x49\x36\x8b\x23\xd4\xd6\xd5\x11\xf7\ +\x00\xbb\x4e\x19\x7d\xea\x43\xa3\x4f\x3d\xf5\xd7\x03\x07\xee\x47\ +\x39\xb9\xb9\x90\x08\x05\xd5\xff\x86\x44\x27\xbe\xc2\x5f\x9e\xfa\ +\xd2\xa3\x4f\x3f\xf9\xc4\xdf\x76\x96\xef\x2c\xca\xce\xce\x16\x5e\ +\x8b\xf0\x5a\x21\x02\x71\x33\x35\x62\xc8\xf8\xb0\x6d\x96\xd0\x70\ +\x86\x74\x76\x28\x0e\x42\x4b\x8e\x82\xca\x17\x32\x0a\x51\x72\xbe\ +\x82\x31\x0a\xfb\x21\x01\xd1\x74\x6e\x23\x74\xca\x17\x5a\xfe\xb4\ +\x97\x5e\xfc\xd5\xf3\xcf\x3e\xfb\x52\x5d\x5d\x5d\xb6\xce\x0e\x85\ +\xc0\x0e\xd0\x50\x5f\x2f\x9e\x89\xf0\xc4\xe4\x49\xbf\x7b\xf5\xe5\ +\x69\xb7\xa2\x91\x72\xd5\xef\x26\xb4\x42\xed\xbb\x05\x72\x45\x87\ +\x00\x2e\xaa\xbc\xbc\x3c\x9a\xf3\xc1\xac\x71\xbf\xf9\xd5\xc3\x2f\ +\xd4\x54\x57\x67\x60\xa8\x80\x2d\x82\x22\xf0\x10\x50\x5d\x5d\x4d\ +\x39\x39\xd9\xf4\xca\xb4\x69\x57\xfd\xf6\x57\x0f\xff\x25\x97\x1b\ +\x86\x06\xd6\xd5\xd5\x53\x43\x63\x83\x74\xcb\xaa\xab\x56\x57\x17\ +\xe8\x5c\xe9\xb2\xc0\xd3\x43\x80\xe4\xa5\xa1\xd3\xa3\x5a\x9e\x40\ +\xa2\x83\x47\xd7\x6d\xf8\xd0\x58\xe7\xac\x4c\xea\x9c\x91\xc9\x2c\ +\x4e\x78\x86\x80\xfa\xfa\x06\x71\xc0\x4e\x72\x15\xbb\xe5\x70\xec\ +\x6c\x6e\x9b\x1c\x03\x3c\x11\x57\x34\xce\x17\x93\x55\xb9\xfa\x91\ +\xc1\x90\xee\x96\x15\xc9\x13\x2f\xb9\xda\xd0\xed\xda\x5d\xb0\x6a\ +\x5f\x1d\x35\x36\x34\x48\x3d\xa2\x33\x7c\xb8\x0c\x57\x46\x99\x5c\ +\x4e\xd2\x76\x19\x0e\x8d\xac\x87\x5a\x1e\xaf\xa5\x5e\x9e\xea\x49\ +\x39\x2e\xd2\xc8\x43\x44\x56\x56\x16\x17\x4d\x67\xbe\x14\x54\x65\ +\x55\x61\xd1\x2d\x0c\x6b\x1f\x0b\xc3\x0d\xe4\xb3\x58\x1f\x28\x53\ +\xb1\xb3\x82\x2e\xbf\xe2\x27\xbf\xfe\x9f\x9b\x6e\xbe\x5b\xd9\x22\ +\x07\xd2\xad\x46\x60\x07\xc0\xb8\xbf\x79\xd3\xa6\xfe\xd7\xfd\xec\ +\xa7\x4b\x2a\x2a\x2a\xf6\x80\x12\xea\x79\x9c\x1a\xc0\x63\xd3\xd8\ +\x71\xe3\x28\x3f\x8f\x67\xab\xbc\x41\xc9\x38\x99\x25\x5f\x2c\xa6\ +\x99\x33\x66\x50\xa7\x8c\xce\x62\x10\x33\x07\x10\x70\x74\xee\x79\ +\xe7\xf3\xcc\x76\x7f\x39\x49\xc3\xe6\x49\x24\x4d\x7f\xe5\x15\x2a\ +\xdd\xb6\x8d\x3a\x77\xc6\x7c\xc2\x75\x80\x7a\xf6\xfa\x03\x0e\x1c\ +\x4c\xa3\x4f\x3d\x5d\xba\x47\x28\x0e\x05\x9b\x9a\x1a\xe9\xf3\x4f\ +\x3f\xa3\x8f\x3f\x9e\xcb\x65\xe0\x38\xca\x01\xe4\xa0\x7c\xae\x19\ +\xdc\xce\x33\xcf\x1c\x43\x7d\xf6\xde\x5b\xf3\x15\xb6\x97\x6e\xa7\ +\x37\xdf\x7c\x43\x56\x31\x8e\x13\x30\x1f\xfa\xa9\xab\xab\xa5\x43\ +\x87\x0e\xa3\x1f\x9e\xf8\x23\x36\x76\x67\xe1\xe1\x78\x68\xc3\xbc\ +\xb9\x1f\xd2\xa7\x8b\x16\xb1\x93\x2a\xbe\x32\x1a\x5f\x95\x0d\x8d\ +\x94\x9b\x97\x4b\xe7\x5f\x70\x21\xf5\x2c\xea\x09\xae\x34\x11\xf9\ +\x9b\x36\x6e\xa0\x69\x53\x5f\xa2\x9a\xea\x1a\x69\x1f\xb8\x52\x96\ +\x33\x51\xd7\x0f\x4e\xf8\x21\x9d\x70\xe2\x89\xd2\x9b\x82\x0f\xe7\ +\xc5\x05\x32\xe3\xed\xb7\xe8\x8b\xc5\x9f\x8b\xc3\x35\xb0\x33\x72\ +\x5e\xd3\xef\xff\x34\xf9\x84\x43\x87\x0e\x9d\x2f\x4e\x18\x00\x81\ +\x1d\x00\x46\x79\x7c\xf2\xa4\xa7\xde\x7c\xe3\xf5\x9f\xf2\x2c\x15\ +\x9a\x92\xab\xea\xf1\xa7\x9e\xa6\x03\x0f\x1a\xa2\xa5\x22\x71\xe7\ +\x6d\xb7\xd0\xc2\x05\x0b\xf8\xea\xcc\xd1\x0e\x80\x9e\xa4\x86\xce\ +\x18\x33\x86\x6e\xbb\xe3\x4e\x49\x7b\xb1\x70\xc1\x27\x34\xf1\xfe\ +\xfb\xe5\xa4\xcd\x52\x11\xb3\xea\xec\xec\x1c\xfa\xdd\x9f\x26\x51\ +\x51\x51\x91\x96\xb4\xc0\x6d\xb9\xeb\x8e\xdb\x69\xf5\xaa\x55\x94\ +\xc9\x57\x9a\xb1\x3f\x14\x7e\xde\x05\x63\x69\xc2\xc5\x17\x8b\x98\ +\x17\xb3\x67\xbd\xcf\xe7\x34\x99\x8f\x9d\x85\x43\x08\x1a\x1a\xea\ +\xa9\x6b\xd7\x6e\xf4\xd8\x1f\xfe\x88\xd9\xb8\x62\x5a\x80\x61\x6e\ +\xbc\xfe\x5a\xda\xb2\x79\x33\xf7\x80\x6c\x30\x6d\x4c\xac\x8c\xae\ +\xf9\xf9\x75\x74\xde\xf9\xe7\x6b\xc9\x48\xfc\xe3\xf9\xe7\xe8\x99\ +\xbf\x3c\xcd\x57\x2e\x7a\x45\x75\x85\xe3\x02\xea\xdb\xaf\x1f\xfd\ +\xf5\xef\xcf\xf9\x0e\xa5\xdb\x4b\x4b\xe9\xb2\x8b\x27\x10\x5f\x70\ +\xe2\xa4\xd5\x5c\xc7\x11\x47\x1d\x35\xfb\xde\xfb\x7f\x31\xa2\xa8\ +\x57\x2f\x2d\xd5\x3a\xa0\xc3\x0d\x04\x9e\xf5\xf7\x9e\xff\xf1\xbc\ +\xf1\xea\xea\x53\x33\xe2\x82\x2e\x5d\xe4\xca\x8a\x85\xde\x9c\xd7\ +\xd4\x28\xab\x5e\xb9\x12\x24\xe6\xde\xa1\xff\x80\x01\x3a\x15\x8d\ +\x5e\xbd\x7b\x4b\x77\x69\x3b\x6a\x23\x1f\x63\x8f\xae\x5d\xa9\xb0\ +\xb0\x50\x73\x3c\x60\xe7\x2a\x2a\xea\x25\x43\x11\x2c\x29\x25\x79\ +\x87\xb8\xcf\xde\x7d\x90\xf2\x05\xaf\xb7\x65\x18\x73\xea\xe2\x18\ +\x43\x4c\xb7\x6e\xdd\x7c\x8d\x0f\xa0\x6d\x7b\xf5\x2c\x92\x2b\xde\ +\x06\x7a\xb2\xbd\xe3\xd4\xd5\x7f\xc0\xbe\xdc\x4c\xa8\x5f\xb7\x8f\ +\x81\xba\x7a\xf4\xe8\x11\x73\x1e\xd5\x95\xdb\x51\x58\xb8\x27\xeb\ +\x50\xd5\x95\xc5\xba\xff\xcf\x97\x5f\x9e\xb4\x7c\xf9\xb2\xa3\x84\ +\x11\x00\x81\x1d\xe0\xe3\x79\x73\x4f\xdf\xb1\x63\x47\x81\xdd\x58\ +\x28\x0e\x27\x11\x0b\x30\xbe\x31\x86\x01\xc8\x46\x8f\xf2\x6c\xe0\ +\x78\x4a\x45\xaa\x90\x29\xda\x52\x5d\xb8\xff\x00\x38\xf2\x7a\x1f\ +\xb7\x8c\xe4\xe1\x0a\x96\x48\x95\xe1\x1d\x9c\x1b\xc3\x58\x2c\x98\ +\x3c\x55\x07\x43\x13\x2d\xd7\x15\x8d\xf8\xf5\xb0\x2e\xa4\x71\x0a\ +\xe8\x05\x6a\x6b\x6b\xd2\xe6\xcd\xfd\xe8\x3c\xcd\x6a\x35\x02\x3b\ +\xc0\x8a\xe5\xcb\x4e\xd4\x64\xab\xe0\x0c\xbb\xee\x79\x24\x84\x56\ +\x8a\x33\xb8\x84\x14\x52\x5d\x32\xac\x6a\x0c\x1b\x0f\x46\xbf\xb6\ +\xd3\x39\xcc\x58\x90\x6c\xaf\x0c\xa7\x5b\x28\xe6\x00\x72\x89\xca\ +\xb2\xa0\x2d\x8a\x0b\x70\xd9\xd2\x6f\x7e\xa4\x93\xad\x46\x60\x07\ +\xd8\xba\x75\xeb\x7e\xde\xb5\x3e\x26\x34\xf1\xd6\xff\xf0\xd8\xc8\ +\xe6\x03\xcd\x71\xcb\xc8\xdd\x43\x03\x6d\x41\x6c\x98\x42\xb4\x58\ +\x97\x31\xba\x94\x40\xd4\x42\x5d\x92\x87\x32\xba\x1e\x8e\x40\xe3\ +\xbc\x64\x62\x18\x03\x68\x8b\x1c\x1f\x7b\x55\xa1\xa4\xe3\xd7\x15\ +\xd9\xfd\x1b\xa8\x61\xc1\x1f\xe9\xac\x0b\x35\x69\x74\x81\x79\x47\ +\x69\xe9\xb6\xd8\xe3\x6e\x0b\x08\xec\x00\xbb\x76\xed\xea\x61\x2b\ +\x05\x0d\xc3\x0c\x7a\xd3\xa6\xcd\x9a\x13\x8d\x4d\x9b\x36\x5a\x06\ +\x55\xa7\x8e\x63\x14\x17\xaf\x13\xda\x0f\x25\x5b\xb6\xc8\x52\x4a\ +\x26\x7f\x9a\x87\xf1\x75\x67\xf9\x4e\xf9\xce\x21\x16\xb6\x70\xb9\ +\x74\x18\x80\x0d\xa2\xec\xa9\x0c\xbb\x91\xdb\x10\x0b\xeb\xd7\xaf\ +\xe7\x35\x75\x83\xf4\x52\xa6\x0c\xda\x87\x7a\xaa\x2a\xab\x44\xc6\ +\x8b\x3a\x9e\xb8\xf1\xc5\xe0\x18\x5b\x8a\x61\xe3\xae\x1c\x77\x47\ +\x63\x01\xdf\x9d\xa0\xbb\x57\xe6\x74\x75\x81\x89\x5e\xac\xe1\x01\ +\xab\xa2\xed\xdb\xb7\x47\x38\x23\xe8\xea\xea\xaa\xc0\xb7\x04\x03\ +\xaf\x02\xce\x18\x7d\x4a\x31\x37\xa8\x1f\x4e\x1c\xc6\x47\xc0\xb2\ +\x68\xbf\x41\x83\xe8\xc2\x71\xe3\x79\xc2\xd2\x55\x9d\x17\xf3\x71\ +\x42\x9f\x2e\x5a\x48\xef\xf0\x32\x46\xc9\xf3\x09\xf0\x99\x8b\x37\ +\x8b\x92\x3b\xc9\x6c\xf9\xc0\x21\x07\xcb\x9a\x5e\x17\x63\xcf\x2e\ +\xa5\x57\x5f\x9e\x46\x5b\x4b\xb6\x52\x06\x2f\x03\xe1\x04\xa6\x5c\ +\x7d\x5d\x3d\x1d\x34\x64\x08\x9d\x76\xc6\x19\x94\xc7\x4b\x4e\x5d\ +\x99\x2c\x8f\xb0\x72\x98\xfb\xe1\x87\xbc\xae\xef\x2c\x3c\x2e\x22\ +\x07\x84\x51\xb0\x9a\x38\xeb\x9c\x73\x64\xe2\x69\x3b\x55\x49\xc9\ +\x16\x7a\x7d\xfa\x74\x51\x32\xda\xe8\xea\x05\xcb\xc0\x3a\x1a\x36\ +\x6c\x38\x9d\x3c\xf2\x14\x99\xf4\x99\xba\xb0\x64\x9b\x33\x7b\xb6\ +\xac\x6c\xd0\x3e\xb0\x51\x0e\x1b\xce\x19\x37\x6d\xc6\x5e\x38\x8e\ +\x27\x9e\x7d\xe5\x48\x02\xce\x5f\xb7\x6e\x1d\x4d\x7b\xe9\x45\x5e\ +\x29\x54\xca\xca\x49\xea\xd2\x65\xb1\x12\xc0\x12\xf0\xa4\x11\x23\ +\xf5\xfd\x05\xce\xe0\x13\x80\x03\xf2\x8a\x8b\x16\x7f\xfe\x19\x2f\ +\x6f\xf5\x92\x13\x79\x72\xc8\xe6\xb2\x8f\xe6\x2f\x88\x31\x23\x8e\ +\x8f\x36\x73\x00\x00\xde\x08\x65\x61\x52\x97\xce\x5d\x9c\x71\x0c\ +\x39\x03\x3e\x43\xdc\xac\xb0\x79\x6a\x59\xa7\x20\x6b\x62\x3e\x16\ +\xb3\x18\x4a\x06\x8a\xc4\x77\x0a\xb8\x41\x03\x05\x49\x39\x7c\x70\ +\x0c\xee\xbc\x60\x00\x2c\x09\xe5\xa6\x8e\xca\xe0\xb2\x6a\xdd\x2c\ +\xab\x13\xc8\xe9\xe3\xc9\x9e\x13\xb8\xea\x9c\x1b\x41\xcc\x33\x67\ +\x6f\x6e\x04\x79\x8d\xaf\xc8\x66\xe9\x85\x9a\xb8\x2e\x39\x16\x94\ +\x8f\xad\x49\xc9\x61\xa9\xa9\x64\x39\x2d\x1f\x15\xc3\x19\x6b\xeb\ +\xf8\xbc\x78\x33\xc7\x41\x0c\xe7\xc8\xe2\xa5\x26\x96\xc2\x60\xab\ +\xe3\xe8\xf2\x0c\xdc\xd8\x11\x9e\x54\xa5\xf8\x4d\x9c\x4e\x67\xe5\ +\xc0\x01\x9d\x49\xa7\xe4\x09\xd5\xf1\x0e\x70\x3a\x3b\x40\x85\xc7\ +\x01\xc4\x30\x42\x6b\xc5\x23\xad\xf9\x8a\x56\x7c\x57\x46\xa5\x4d\ +\x9e\x7c\x84\x06\x38\x56\xde\xa0\x79\x9e\x7c\xcd\x33\xb4\xe4\xc9\ +\x8e\xf7\x86\x36\x79\x12\xe9\x74\x42\x30\x8a\x05\xa9\x08\xe6\x28\ +\x92\x77\xd8\xd4\xc7\x13\x47\xe5\xc9\xde\x35\xb0\x14\x97\x4c\x95\ +\x42\xbe\x44\x92\x23\xb1\xca\x36\x79\x42\x39\x72\xae\x8c\x24\x2c\ +\x1a\x0e\xb0\x30\x90\x03\x04\x9e\x03\xe8\x16\xc5\x40\xbc\x3c\x17\ +\xfa\xf4\xdc\x63\xc9\xb9\x28\x52\xe0\xf0\x2d\x26\x93\x26\x85\xd8\ +\xca\x61\x28\x0e\xc4\x23\x8e\xcd\x41\x2b\xca\xe5\xfb\x40\xe5\x41\ +\x16\x91\x2a\x67\xf8\x8a\x54\xf9\x0e\x20\xe2\x90\x16\x5f\x43\x38\ +\x36\xdb\x87\xf6\x2b\xe7\x8f\x44\xe5\x5a\x87\xe0\x3d\xc0\xa8\x91\ +\xc5\x15\x15\x15\xd2\x03\x00\xea\x6a\x56\x01\x40\x97\x55\xdf\x50\ +\xcf\xed\x56\xb3\x68\xb9\x26\x39\x32\xf9\x2e\xcf\xe6\x83\x50\x34\ +\x36\x97\x96\x02\xec\xad\x8a\x87\x9d\x2a\xa3\xe7\x12\x3a\xad\x76\ +\x2a\x0d\x5a\x52\x7a\xa7\x72\x18\x0e\x01\x98\x84\xa5\x03\xc7\x30\ +\x18\xd2\xd2\xe4\x16\xaf\x3a\xae\xe5\x04\xf8\x70\x02\x49\xac\xcd\ +\x31\x6e\xe3\x7c\x85\x23\x1f\x11\xc0\x5e\xe4\x0c\xcf\xa6\x25\x5f\ +\x22\xde\x99\x3c\x2d\xaf\x48\x8e\xd1\xd5\x73\xdd\x19\xdc\x06\xb4\ +\xc5\xcd\xf7\xca\x37\x97\xcd\xfd\x24\x58\x0f\x10\xd2\x01\x30\x04\ +\xa8\x1b\x41\xca\x80\x2a\xc6\x3c\xa0\x77\xdf\x01\x74\xca\x59\x17\ +\x51\xf7\x1e\x45\x5a\xcd\xbc\x57\x84\xd2\x67\xa4\x25\x18\x8e\x54\ +\x14\xf8\x14\x79\x1f\x9d\x1f\x8b\xef\x07\x57\x32\x31\xb4\xee\xd8\ +\xed\x23\xfb\xc9\x7b\x2f\x50\xe5\xae\x4a\x5a\xbd\x66\x35\xf1\x70\ +\x1b\x71\x47\xf4\xbf\xc2\x01\xbc\xab\x00\x20\x2b\xb7\x80\xc6\x5c\ +\x78\x25\x1d\xfd\xa3\xb3\xa9\xb9\x13\x26\x47\x29\x04\x45\x6e\x67\ +\xdc\xca\xe6\xc9\x64\xd5\x56\xfa\xfc\xf3\x2f\xe8\xe5\xe7\x26\x51\ +\x4d\x65\x85\xe4\x69\xc3\x83\xe2\x98\x02\x3b\x40\xf0\x39\x80\x07\ +\x68\x4c\x6e\x41\x57\x3a\xed\xbc\x2b\xe8\xa8\x11\x17\xb2\xf1\x83\ +\x7d\x3b\x95\x82\x8b\xaa\xfa\x0c\xaa\x6a\xc8\xa0\xba\xcc\x5e\x74\ +\xc8\xb1\x67\xd0\xdd\x8f\x4d\xa3\x3e\xfd\x07\x6b\xc3\x2b\x04\xbb\ +\x7c\x5d\x04\xef\x01\x4e\x19\x51\xbc\xd3\x99\x03\xa8\x31\xf8\xf8\ +\xd1\xe3\xe8\x9c\x4b\x6e\x52\x02\x1a\x7b\x04\xfb\x9a\x7a\xb7\x02\ +\x3a\x31\x3d\xda\xee\x44\x65\x6d\x33\x35\x34\x45\xb6\x63\xc5\x7f\ +\x16\xd0\x5f\x7f\x7b\xb3\xd0\x68\xa7\xd8\x0f\x43\xc0\x82\x45\x1d\ +\xdb\x03\x28\xb7\xc1\x5e\x07\x6e\xc8\x81\x43\x8f\x11\xae\x41\x7a\ +\x5a\xb3\x7c\x29\xf3\xff\x2d\xe0\x8c\xfc\xf8\x1d\x1d\x3a\x77\xc2\ +\x8f\x5b\x94\x2e\x0d\x32\xb3\x72\xe4\x3e\x80\xba\x70\x11\xcc\x3e\ +\x18\x02\xf7\x00\xa7\x71\x0f\x80\xfb\x00\xb8\xdd\x6a\xae\x96\xab\ +\xef\xfc\x23\x1d\x70\xe8\xd1\x42\xa3\x59\xe0\xaa\x7d\x0a\x6d\x85\ +\x75\xdf\xfe\x87\x26\x3d\x70\xb5\xe8\x5c\x5f\xfd\x70\x80\xb2\x79\ +\x1d\xdd\x03\x00\xae\xeb\x18\xca\x76\x26\xdc\xe5\x4a\x19\xbf\x3d\ +\xd0\x56\x57\x3f\xd0\x66\x93\xc0\x14\x76\x27\x82\xbb\x41\xf0\x39\ +\x80\xf1\x42\x74\x41\x52\x7f\x58\x5f\x4c\x21\x11\x98\x21\x5b\xa9\ +\xdf\xa2\x03\x22\xdc\x10\xc0\x15\x9b\xba\xc3\x34\x22\x85\xd6\x42\ +\x1b\x5e\xf6\xe1\x10\x78\x12\x78\xea\xc8\x93\xdd\x1b\x41\x60\xf0\ +\xa4\xe4\xa7\x77\x61\x12\x18\xb9\x12\xe8\x08\xec\x2c\x2f\xa3\xd9\ +\x33\x5f\xa1\xef\xd6\x7e\x4b\x25\x9b\xd6\x53\xc9\xe6\xf5\x54\xb8\ +\x67\x4f\xea\xce\x61\xff\x83\x86\xd1\xa8\x31\xe3\x29\xbf\xcb\x1e\ +\x5a\x3a\x3c\xa6\x3d\x37\x49\xea\xc9\xcd\x2f\xa0\xfe\x03\x07\xd3\ +\x88\xd3\xc7\xea\x9c\xf6\xc7\xda\x15\x5f\xd2\x9f\xee\xbf\x4a\x7e\ +\x13\x81\xe9\x9f\x4c\x01\x79\x19\xf8\xf1\xc2\xcf\x3a\xf6\x4e\xe0\ +\xe8\x11\x27\x45\xde\x0a\xe6\x70\x15\xaf\x02\x0e\x1c\x76\xac\xa4\ +\x3b\x02\x25\x9b\x37\xd0\x23\xf7\x5d\x47\x73\x67\xbd\xa9\x39\xb1\ +\x31\xf6\xd2\xeb\xe9\xe6\x7b\xff\xe0\xfc\x70\x23\x08\x16\xce\xfd\ +\x37\x3d\xfe\xc8\xdd\xb4\xfc\xeb\xcf\x35\x87\xe8\xe0\xe1\xc7\xd2\ +\x33\xaf\xce\xd7\xa9\xf6\x87\x71\x00\xb3\xf2\x82\xfd\x38\x94\xcd\ +\x5f\x14\xcc\x01\xc2\x4d\x02\xe1\x7c\xd8\x29\xb2\x43\xf1\xc1\xbb\ +\xd3\xe9\xd2\x31\x87\x25\x64\x7c\xe0\xe5\xe7\x27\xd3\xf8\xd1\x07\ +\xd3\xaa\xe5\x5f\x69\x4e\xe2\xd8\x55\xb1\x93\x7e\x73\xef\xb5\x74\ +\xc3\x65\xa3\x22\x8c\x0f\xc8\x17\x36\x1d\x0d\xe7\xa2\x45\x1c\x4e\ +\xf3\xe1\x97\x81\xd2\x18\xbb\x41\xed\x8f\x6f\x97\x7d\x49\xf7\xde\ +\x34\x81\xca\xcb\xb6\x69\x8e\xc2\x91\xc7\x8f\xa4\xb3\xc7\x5d\x4d\ +\x17\x5d\x75\x1b\x1d\x7f\xd2\x19\xd4\xad\x70\x2f\x9d\xa3\x50\xbc\ +\x66\x39\x3d\x70\xeb\xa5\x54\x53\x53\xad\x39\x2d\xe3\xed\x57\x9e\ +\xa5\xb1\x23\x07\xd3\xf4\x17\x9e\xd0\x9c\x48\x98\x0b\xa0\x23\xa1\ +\x6a\x94\x2b\x5f\xfb\x42\xf0\x36\x84\x5f\x05\x08\x2d\x7b\x5a\xf1\ +\xd5\x22\x49\xb7\x37\x1e\xba\xf3\x4a\xaa\xaf\xab\xd5\x29\xa2\x81\ +\x07\x1c\x42\x4f\x4f\x9b\x47\x93\xa7\xfc\x9b\xee\xf9\xd5\xd3\x74\ +\xc3\x3d\x8f\xd0\xef\x9e\x79\x9b\xa6\xcf\x59\x4d\xe3\x2e\xbf\x51\ +\x4b\x29\xac\x5c\xb6\x84\x7e\x3f\x31\xf2\x76\xb5\x1f\xd6\xac\xfc\ +\x86\x6e\xbb\xfa\x6c\xfa\xe5\x1d\x57\x50\x59\xe9\x16\xcd\x8d\x46\ +\xd0\x21\x34\x28\x4c\x7d\x96\xfa\xdd\x38\x00\x42\x0f\x01\xaa\x72\ +\xe5\x89\xa5\x5b\x36\x20\xd1\xae\x78\x63\xea\x33\x11\xdd\x30\xae\ +\xf2\xdf\x3e\xf9\x1a\x0d\x3d\xe2\x78\xcd\x71\x91\x9b\x97\x4f\xb7\ +\xdc\xf7\x07\x3a\x77\xfc\x35\x9a\xa3\xf0\xfa\x4b\x7f\xa1\x9d\x3b\ +\xb6\xeb\x54\x34\xe6\xcd\x7a\x9b\x87\x8b\x21\x51\xc3\xcb\xd5\x37\ +\xfd\x82\xee\x98\xf8\xb8\x4e\x29\xec\x96\x21\xc0\x55\xbc\xc4\x86\ +\x0a\x82\xd0\x43\x80\x54\xee\xee\xda\x1d\x53\x9f\xfd\xa3\xa6\x14\ +\x7e\x7e\xdb\xc3\xb4\xf7\x3e\x03\x75\xca\x1f\x77\x3d\xf4\x24\xed\ +\xd5\xcb\xfa\x61\x26\xb7\xf5\x8d\x69\xcf\x68\x3a\x1a\xf3\x66\xbf\ +\xad\x29\x85\xd3\xcf\xbb\x8c\x66\x2e\x2a\xa1\xab\x6e\xb8\x4f\x73\ +\x5c\x74\x74\x0f\x00\x98\xab\x5f\x22\xa9\x3e\x78\x1b\x42\x38\x80\ +\x6e\x05\x07\xd3\x86\x78\xff\x6a\x69\x0b\x7c\xbd\x64\x21\xad\x5e\ +\xe1\x4e\xe2\xfa\xf4\x1b\xc8\x63\xfe\x95\x3a\x15\x1f\xa3\xce\xfc\ +\xb1\xa6\x14\x3e\xfb\x78\x96\xa6\xa2\x91\x9b\x57\x20\xf1\x90\xa1\ +\x47\xf3\xb0\xf2\x3e\xdd\xff\xe8\xb3\xbc\xa4\x8c\x9c\x4f\x18\x74\ +\xfc\x10\x00\x1d\x9b\xab\x5e\xd7\x1d\xa2\x09\x21\xe6\x00\xd8\xe9\ +\xd8\xdb\xa0\x76\xc2\xa7\x1e\xa3\x9d\x7c\xda\x05\x9a\x6a\x19\xa7\ +\x8c\x89\x74\x80\x4f\xe7\xcf\x92\x9f\x72\xf9\xe1\xa4\x53\xcf\xa3\ +\x89\x7f\xf8\x27\xfd\xed\xb5\x05\x3c\xb1\x1c\xa1\xb9\xfe\xd8\x3d\ +\xab\x00\xb5\x53\x36\x80\xee\x83\xeb\x3d\x54\x0f\xa0\x2a\xd6\x0d\ +\x09\xd1\x88\x44\xf1\x19\x1b\xcd\xc6\x21\x87\x25\x7e\xcf\x61\xf0\ +\xc1\x87\x51\x56\xb6\xfb\xff\x09\xfc\x96\xcf\xbb\xa4\x33\xc0\x71\ +\x47\x9f\x35\x5e\xa7\xe2\x23\x8c\xf2\x83\xc2\x55\x77\xf8\xda\x83\ +\x3b\x00\x6a\x36\x01\x51\xd8\x96\x24\x80\xf5\xc5\xab\x34\xa5\x30\ +\x60\xe0\x81\x9a\x4a\x0c\xfd\x06\xec\xaf\x29\x85\x4d\xeb\xd7\x6a\ +\x2a\x38\x76\xc7\x1c\x00\x4a\x97\x5a\xf5\x2e\x4c\x13\x82\x0f\x01\ +\x12\xd4\xe6\xb6\x20\x44\x4b\x5a\x00\x1e\x83\x52\xb2\xe9\x3b\x9d\ +\x52\xc0\x0f\x4e\x5b\x83\x28\x07\xd8\x10\xfb\x2f\x69\x89\xa2\xbd\ +\xe7\x3d\x5e\xc0\xe1\x44\xdd\x88\x45\xf7\xc2\xc5\x2e\x10\xc2\xf7\ +\x00\x12\xa1\x21\x08\x2a\xdd\x1e\xf0\xbb\x5a\xf3\xf2\xd5\x64\x2d\ +\x51\xe0\xbb\x01\x1b\xdb\xb7\xc5\xfe\x1f\x63\xc2\x70\x9c\xbf\x63\ +\x21\x3a\xd7\x71\x98\x26\x84\xe8\x01\x54\x13\x4c\xe5\xa6\x41\xed\ +\x85\xca\xca\xef\x35\xa5\x90\x93\x9b\xef\xdc\x0f\x4f\x14\xd9\xf2\ +\x34\x0e\x17\xb1\x26\x81\xad\x41\xc7\xaf\x02\xb8\x3e\x5d\xa7\x44\ +\x21\xab\x0f\x31\x09\x04\x74\x63\x74\x23\x42\xb6\x25\x2e\xaa\xab\ +\x76\x69\x4a\xc1\x2c\xd5\x5a\x03\xaf\x03\xe0\xf1\x2f\x61\xd1\xd1\ +\x43\x00\x20\x7a\xc6\x8e\x75\xaf\x74\x1e\x5c\xf3\xc1\x7b\x00\x5d\ +\xa7\x6a\x87\xea\x86\x9a\x79\x66\xdd\x5e\xa8\xaa\xf4\x38\x40\x2b\ +\xbb\x7f\x20\x27\x27\x4f\x53\x0a\xf5\xf5\x6d\xd0\x03\x84\x50\x7e\ +\x20\x88\xe2\xa1\x6f\xd7\xf8\xc6\x16\x41\x10\xa2\x07\x50\x8d\x70\ +\x54\xe0\x34\xa8\x7d\x60\xff\x27\x1e\x68\x0c\xf1\x6c\x3c\x83\xac\ +\xac\x36\x78\xd6\x62\x18\xed\x07\xc0\xaa\x6f\x16\x4b\x95\xaa\x56\ +\x6d\xfc\x10\x6d\x08\x37\x04\xa0\x21\x52\xb7\x71\x02\xec\xda\x07\ +\x18\xf3\x6d\xe0\xaf\xe1\xad\x45\x95\xcf\x3c\x22\x2c\x3a\x7a\x08\ +\x28\x2d\x59\xaf\x95\xae\x8d\x1f\x52\xe9\x21\x86\x00\x6f\xc5\xed\ +\x68\x7d\x46\x4e\x6e\xf8\xee\x3b\x6a\x22\x29\x0f\x96\x08\x87\x68\ +\x3d\xb4\x2f\xe4\x3f\x01\x9a\x16\x70\x22\x4c\x13\x42\xf5\x00\x72\ +\xf2\x1c\x74\x04\x9f\xd4\x39\x6d\x0f\xef\xa4\xaf\xa2\xbc\x4c\x53\ +\x89\xc3\x5b\xa6\x6b\xb7\x3d\x35\x95\x38\xa2\x56\x1e\x61\xb4\x1f\ +\x18\x6e\xd7\x1f\x56\xef\xc1\x7b\x00\x69\x84\xdb\x10\xa7\x51\xed\ +\x84\x1e\x3d\x7b\x6b\x4a\x01\x5f\x8a\x94\x95\x6e\xd5\xa9\xc4\xb0\ +\xf1\xbb\x35\x9a\x52\xc0\x3f\x98\x5b\x0b\x3c\x59\xc4\x46\xc7\xaf\ +\x02\x5c\x9d\x23\xe6\xbd\xf0\x82\x22\x78\x0f\xa0\xeb\x44\x03\xb4\ +\xfd\x39\xb4\x9f\x32\x30\x04\xe4\x17\x74\xd5\x29\x85\x6d\x25\xb1\ +\x1f\xf8\xe4\x87\x4d\xeb\x23\x1d\xa0\x4f\xdf\x7d\x35\x95\x38\xbc\ +\x3d\x80\x32\x40\xc7\x41\x5d\x64\xa6\x56\xad\xf8\x10\x4d\x08\x35\ +\x07\x50\xcd\x50\x71\x47\x8c\x85\x3d\x8a\x22\x9f\xbc\xb9\x74\xc9\ +\x42\x4d\xb5\x8c\xed\xdb\x4a\x68\xab\xf5\x83\x15\x3c\xb3\x78\xc0\ +\xa0\x83\x74\x2a\x71\x58\x8f\x9a\x10\x74\xf4\x1c\x40\xbe\x7d\x14\ +\xb5\x6b\xfd\xcb\x27\x78\x1b\x42\xcd\x01\xa4\x5e\xa9\x5b\x35\x61\ +\xcd\x8a\xaf\xb8\x4b\x6c\xbf\x7b\x01\x47\x1e\x17\xf9\xd5\xec\x57\ +\x5f\x2c\xd0\x54\xcb\xf8\xe4\xc3\x99\x9a\x52\x38\xea\xf8\x91\x81\ +\x7e\x21\xec\x1d\x02\x76\xc7\xd7\xc1\xce\xc5\xa7\x3e\x7a\x17\x0c\ +\xc1\x7b\x00\x67\x93\x84\xec\x2a\x76\x6c\xa3\x86\xfa\xd6\x2f\xcf\ +\x12\x85\xf7\xbb\xf9\x59\x33\xa6\xe1\x51\xa9\x3a\x15\x1f\xf3\xe7\ +\xbc\xa3\x29\x05\xaf\x33\x25\x8a\xa8\x21\xa0\x83\x7b\x00\xa5\x79\ +\x89\x74\xac\xd3\x01\x11\x6e\x0e\x20\xc1\x6e\x10\x76\x92\x6a\x17\ +\x1c\xf7\xa3\xd3\xa9\x4b\x57\xf7\xe7\xef\xb5\xb5\xd5\xf2\x27\x8d\ +\x96\x30\x6f\xf6\x0c\x9a\xf5\xce\xcb\x3a\x45\x94\xd1\x39\x93\xce\ +\xbc\xe0\x72\x9d\x6a\x1d\x76\xb7\x03\xa8\xda\x8c\xce\xdd\x38\x28\ +\x42\x0c\x01\xa8\xd4\x6e\x48\xf0\x46\x24\x0a\x3c\x17\xf7\xc2\x4b\ +\xaf\xd7\x29\x85\xc9\xbf\xbe\x83\x3e\x5f\x30\x47\xa7\xa2\xb1\x79\ +\x63\x31\x4d\xfe\x4d\xe4\xa3\xe8\x7f\x7c\xf9\x8d\xb4\x47\xb7\x40\ +\xff\xa3\x88\x1a\x02\x76\x0b\x44\xf5\x6d\xa3\xfb\x50\x3d\x80\x38\ +\x9e\x6e\x08\xe8\x8e\xb8\x1a\x2e\xb8\xe4\xba\xa8\xaf\x75\xaf\x9d\ +\x70\x12\x4d\x79\xfa\x11\x2a\x2f\x2b\xd5\x1c\xe2\x09\xdf\x46\x7a\ +\xf7\xf5\x17\xe8\xa2\xd3\x0e\xa5\xb5\x2b\x97\x6a\x2e\x51\xdf\x01\ +\xfb\xd3\xe5\xd7\xdd\xa3\x53\xb1\x81\x9f\x9f\xcd\x9f\x33\x93\xe6\ +\xbe\xff\x56\x44\x58\xf9\xcd\x12\x2d\xe1\x62\xc1\x47\xff\x12\x79\ +\x3b\xac\x5b\xbd\x5c\xe7\xb6\x2d\x30\xe7\x70\x4c\x6e\x8c\x1f\x42\ +\xed\x81\xff\x1a\x76\xc2\xb1\x47\x15\x97\x97\x97\xeb\xff\x06\xaa\ +\x6e\x11\x4f\xc6\x7c\x7c\xfa\x62\xca\xca\x09\x7f\x87\x2d\x1e\xf0\ +\xb3\xed\x5b\xaf\x1e\xa3\x53\x91\xe8\xda\xbd\x87\xac\xcd\x2b\xca\ +\xfd\x7f\xf6\x8d\xff\x0f\xf8\xfd\x84\xdc\xc6\xcc\xd7\xfe\x41\x0f\ +\xdc\x7a\x89\x4e\x05\x43\x76\x4e\x1e\x7d\xb8\x34\xf2\x0b\xac\xb6\ +\xc0\x33\x8f\xde\x46\x0b\xe7\xcc\x90\xa1\xc8\x18\x9f\xe3\xb2\x2f\ +\x97\x2e\xef\xe0\xbf\x86\xc1\x6f\x74\x50\x7e\xa8\xb6\x8e\xc0\x0f\ +\x46\x9c\x49\x0f\x3c\x36\x85\xba\xec\xd1\x5d\x73\x5c\xe0\xdf\x42\ +\x7e\xc6\x1f\xb0\xdf\x41\xf4\xe4\x4b\x1f\xb5\x68\x7c\x60\xfd\xba\ +\x95\x9a\x0a\x8e\x9a\xea\xca\x56\xdf\xa8\x4a\x04\x66\x05\x20\xba\ +\xd6\xba\xc7\x27\x28\x02\x3b\x80\x74\xf9\x7a\x73\x1a\x10\xa2\x21\ +\xad\xc5\x69\xe7\x5e\x4c\x2f\xfe\xeb\x6b\x1a\x7f\xe5\x2d\x54\xd8\ +\x23\xf6\xeb\x52\xf6\xd9\x77\x30\x5d\x73\xcb\x2f\xe9\xf9\xb7\x16\ +\xd3\xf0\xa3\x4e\xd0\xdc\xf8\x38\xf4\xf0\xe3\x34\x15\x1c\x83\x0f\ +\x39\x22\xe6\x4f\xc9\x43\x01\x3a\xd6\xc1\xd1\x3d\x42\x40\x04\x1e\ +\x02\x7e\x70\xf4\x91\xce\x10\x80\x11\x00\xc3\x00\x9e\x16\xfe\xe4\ +\xeb\x4b\xda\x7d\x08\xf0\x03\xfe\x33\x50\x56\x5a\x22\x01\x2f\x8b\ +\xc2\x3f\x86\x10\x0e\x3c\xe4\x70\x2d\xd1\x3a\x84\x79\x15\x1b\x90\ +\xd1\x19\x4f\x2a\x6f\x7b\x3c\xfd\x9b\x9b\x69\xd1\x47\xef\xa8\xd5\ +\x08\xec\x2f\xf6\x6b\x2e\xfb\xcf\xb2\x6f\x3b\xf6\xef\xe1\xc7\x1f\ +\x7d\x44\x71\xf9\x0e\x3d\x07\xd0\x4b\x23\xcc\x01\x76\x97\x03\x24\ +\x0b\xc4\x01\x3e\xc4\x1c\x40\x3f\x66\x5e\xf5\x03\x65\x5f\x05\x74\ +\x80\x70\x73\x00\xd9\x71\x03\xb8\x21\x66\x4b\xa1\xfd\x01\xbb\x5b\ +\xc6\x57\x66\x08\x88\xe0\x73\x00\x5d\xb9\xaa\x9b\xf7\x92\x08\xd1\ +\x92\x14\x12\x83\xa8\x5a\x94\x2d\x7b\x37\x1d\x0c\x21\x57\x01\x52\ +\xbb\x22\xb1\xa5\x1c\xa0\xdd\x61\x5e\x27\x23\x9a\x86\xee\xb5\x0d\ +\x82\x22\x5c\x0f\xe0\x34\x40\x35\x02\x8d\xab\xab\x4d\xfc\xe1\x0b\ +\x29\xb4\x0e\x8d\x0d\xf5\xb4\x74\xc9\x7c\x75\xdf\x85\x75\x6e\x2e\ +\x38\xd8\x22\x28\x42\xf5\x00\xaa\x62\xed\x08\xbc\xe1\x56\xed\x9c\ +\x99\x53\x55\x7e\x0a\x6d\x8e\x39\x33\x5e\x90\x7b\x1c\xd0\xb5\xb2\ +\xbd\x50\x1c\x49\x22\x10\x42\xf5\x00\xca\x0b\x55\x0a\x1f\x3c\x36\ +\xf6\xdd\x57\xff\x4e\x8b\xe6\x24\xf6\xdc\x9e\x14\x12\xc7\xae\x8a\ +\x1d\x34\x7d\xca\x24\xf5\x56\x51\xad\x73\xd1\x3d\x6c\x80\x64\x40\ +\x04\x5e\x06\x1e\x7d\xf8\xf0\xe2\xf2\xf2\x1d\xfd\x32\xcc\x77\xea\ +\xbc\x14\x94\xae\x89\x3f\x39\x79\x5d\xe8\xf8\x11\xe7\xd0\x09\xa3\ +\x2f\xa0\xcc\x4c\xf7\x9d\x01\x11\x5f\xa4\x45\x24\x50\x2c\x32\x1d\ +\x05\x8f\x7c\x3c\x38\xff\x4f\x68\xc7\x3a\xbc\xf0\x7e\x4b\x98\x08\ +\xa0\x7b\xfc\x30\xc5\xd0\x2e\x5c\x1a\x6f\x2c\xc7\xd3\x4c\x5e\x7c\ +\xea\x61\x79\x4e\x30\x60\x5f\xf5\x88\xf8\x53\xb6\x6c\xe5\xea\x8e\ +\xbd\x0f\x70\xf4\xe1\xc3\x9c\xfb\x00\xd0\xab\x9c\x3e\x2b\x41\xa9\ +\x41\xdd\xa7\x46\xe3\x9d\xe3\x5b\x79\xfa\x23\x3c\xcd\x51\x7b\xc3\ +\x77\x09\x8e\x34\x01\x08\xdb\xcd\xb3\x11\x65\x5c\x9d\x54\x91\x4f\ +\x81\x04\x80\xff\x22\xa8\xf3\xe3\xf2\x72\x1a\xae\xae\x0c\x85\xdf\ +\x26\xea\x37\x79\x3b\x4c\xe7\x9a\x8c\x88\x4c\xbe\xce\x75\xf2\x1c\ +\x42\xd1\x3a\x53\x45\xea\xb1\xf5\x78\x14\x9f\x72\x30\x97\xaf\xc5\ +\x0c\x87\x1d\x60\x4d\x07\x3b\xc0\x61\x43\x8b\x77\xc0\x01\x32\xf4\ +\x97\x41\xea\xc3\x30\xb4\x4e\x49\x64\x78\x9a\xd6\x91\x6d\x4c\xc7\ +\x80\xbe\x69\x27\xa5\xe0\xe5\x45\x64\x02\x2e\x23\x2a\xab\x95\x88\ +\xd4\x8e\x47\x57\x3a\xa9\x22\xde\x5b\xd9\x5e\x9e\x36\x94\x6f\x5a\ +\x68\x9d\x74\x72\xf4\xce\x98\xc7\x95\x71\xf3\x2d\x5e\xd9\xb2\x55\ +\x6b\x3b\xf6\x46\x90\xd4\x2b\x0d\x40\x33\x78\x53\xa4\xcb\xe3\x2b\ +\x03\xce\x65\x82\xe2\x21\x17\x42\x42\x58\x79\x2e\xed\x0d\xbc\x93\ +\x20\x69\xd9\x14\xcb\xe1\x21\xe0\x85\x4d\x08\x3a\x8d\x3c\xde\x49\ +\x08\xbb\x99\xe3\xe0\x98\xf1\xea\x93\xc8\xd4\xa8\x79\x8a\xef\x1f\ +\xd4\x21\x5d\x1a\x3b\xd9\x40\x6b\xbe\x1b\xf0\x3b\x40\xc9\x90\x48\ +\x02\x6f\x2e\x0f\x71\x30\x04\xee\x01\x8e\x1a\x8e\x1e\xa0\x8c\x7b\ +\x00\xbc\xd1\x13\xe0\x2b\x32\x3d\x4d\x5e\xb0\xd8\xc8\x63\x30\x5e\ +\x8a\x28\x3c\x7d\x09\xa2\x9e\x9c\xdc\x5c\x79\xc4\xa9\x80\xf9\xa6\ +\x1c\xbe\xbe\xc5\xb3\xfb\xd4\xbb\x71\x85\xc9\xc0\xf3\xf0\x9b\xe4\ +\xbe\x3e\xde\xa0\x89\x13\x36\xf2\x2a\x42\x5d\x35\x52\xd6\xbc\x5f\ +\x50\xa0\x4f\x07\x2f\xa9\x54\xa2\x6e\x1e\x8e\x8d\xa5\x6a\x0d\x97\ +\xf3\xfe\xd5\x0c\xc7\x41\x3d\xea\xad\x9c\x9a\x29\x40\x22\x8d\x6a\ +\xf0\x32\x47\x64\xd8\x55\x89\x9c\x7a\x21\xa6\xa9\x17\x84\x2a\x91\ +\x26\x6f\x4d\x83\x3e\x54\x5d\x4a\x00\x65\xf0\xbb\x49\xfc\x2d\x0d\ +\xbd\x27\x18\xfa\x30\xb2\x43\x54\x5d\xe5\xbe\xa6\xd6\xd4\xa1\xea\ +\x4e\xa3\x9c\xec\x1c\x45\x6b\x59\x2d\x50\xb6\x7c\xf5\xba\x8e\x1d\ +\x02\x8e\x1c\x7e\x28\xcf\x01\x76\x44\x7c\x19\x54\x5b\x5b\x47\x43\ +\x87\x0f\xa7\xab\x7e\x7a\x8d\xf3\xbe\x7d\xe8\x0b\xca\xc5\xeb\x55\ +\x9f\xfb\xfb\x33\x7c\x0e\xe9\x62\x30\xa5\x47\x65\x64\x38\xd1\x35\ +\x3f\xbf\x8e\x86\x1c\x7c\xb0\x76\x10\x75\xb2\x3b\xca\xca\xe8\xa9\ +\x27\xfe\x4c\x6b\xd7\xae\xa5\x4c\x76\x04\x03\x18\xb2\xa6\xb6\x96\ +\x8e\x3d\xee\x78\x1a\x3f\xe1\x62\xca\xce\xcd\x56\x45\x78\x6b\x68\ +\x6c\xa0\x0f\x3f\xf8\x80\x5e\x9e\xfa\x92\xbc\x3a\xd6\xd4\x04\xe0\ +\x2d\x1c\xb9\xb9\x39\xf4\xb3\x6b\xaf\xa7\x7d\x07\x46\x3e\x59\x6c\ +\x6b\x49\x09\x3d\xf1\xe7\xc9\xf2\x0a\x59\x79\x55\x9c\x06\xb4\x83\ +\x37\x8d\x8e\x1c\x35\x8a\xce\x3e\xe7\x5c\x99\xd4\x6a\xd5\xcb\x97\ +\x5f\x33\x67\xbc\x4d\x33\xde\x7a\x8b\x32\xb3\xd4\xdb\x4d\x0d\x30\ +\x2f\xe8\x5e\xd8\x9d\xae\xbd\xfe\x06\xea\xdd\xa7\x8f\xd3\x0a\x88\ +\x7c\x57\x5c\x4c\x7f\x9e\xf4\x47\x79\xff\xb1\xe8\xcf\x1c\x91\x6d\ +\x51\x57\x57\x4f\xe7\x9e\x7f\x3e\x8d\x3a\xf5\x34\x69\x87\xa9\x0b\ +\x8e\x34\x6d\xea\x8b\x34\xfb\xfd\x7f\xab\xb7\x87\x81\xaf\xeb\xe3\ +\x62\x65\x2b\xd6\x74\xb0\x03\x1c\x73\xf8\xf0\x55\xdb\x4a\xb7\x0d\ +\xc4\xb2\xc4\x18\x19\x27\xf3\xda\x9b\x33\x68\xf0\x41\xfe\x3f\xb7\ +\xbe\xe6\xca\x9f\xd0\x7b\xef\xbd\x4b\x79\xe6\x6f\x5e\x5c\xb0\x72\ +\xd7\x2e\xba\xe4\xb2\x2b\x68\xe2\x43\x0f\x2b\x9e\x07\xf3\xe6\x7e\ +\x44\x57\x5d\x71\x99\x5c\x9d\x66\xa6\xdd\xc4\x57\x71\x7e\x7e\x01\ +\xbd\x3e\x63\x26\xf5\xec\x19\xf9\xeb\x20\x83\x09\x17\x8e\xa5\x2f\ +\x16\x7f\xae\x5f\x21\xab\x78\xbb\x76\x55\xd2\x8d\x37\xdf\x4c\xd7\ +\xdf\xe0\xff\xa0\xc8\xb7\xde\x78\x9d\x6e\xbb\xf9\x26\x76\x12\xf7\ +\x6f\xe4\x30\x72\xaf\x5e\xbd\xe8\x8d\x77\xde\x8d\xe0\x1b\x20\xff\ +\xec\x33\x4e\xa3\x75\xec\xa4\xea\x5d\xc5\x0c\x56\x69\x65\x65\x25\ +\xfd\xe2\xc1\x87\xe8\xa2\x4b\x2e\x55\x3c\x0f\xfe\xf2\xd4\x13\xf4\ +\xf0\x2f\x27\xea\xf7\x1e\x2b\xe0\x07\xae\xfb\x1f\x30\x98\x66\xfc\ +\xeb\xdf\x9a\x13\x09\x5c\x10\xa3\x47\x9c\x44\x65\x65\xdb\x65\x39\ +\x28\x96\x63\xfb\xb1\x0d\xcb\xbe\x5d\xfb\x5d\xc7\xce\x01\xba\xec\ +\xb1\x47\x09\xde\x11\x0c\x07\x82\x0f\xc1\x01\x0a\x0a\xba\x50\x11\ +\x2b\x2b\x16\x7a\xf5\xe9\x2d\x5d\xb0\x94\x11\x0f\xc6\x3b\x71\x9b\ +\xa8\xff\x80\xfe\x5a\x22\x1a\x45\x45\xbd\x28\x9b\xbb\x4b\xc8\xc9\ +\x19\x73\xc0\x31\xf0\x72\xea\x6e\x78\x41\x75\x0c\xf4\xea\xdd\x5b\ +\xcd\xce\xb1\x29\x25\x31\xb7\x39\xf2\x45\xce\x1e\xf4\xdd\x67\x1f\ +\xe9\x96\xf1\x8e\x60\xd5\x42\xf5\x12\xe8\xee\x85\x85\xbe\xc6\x07\ +\x30\x64\xe0\x9c\x51\x17\x8b\x4b\x40\x5d\xf0\xd5\xde\xdc\x86\x58\ +\xe8\xb7\x4f\x7f\x96\x51\xbd\x9d\x6c\x5c\xa6\x91\x7b\xaf\x3d\xf7\ +\x8c\xfd\x77\xb5\x82\x2e\x5d\xa4\x2d\x4a\x87\xaa\x9e\xc6\xc6\x26\ +\xbc\xa4\xda\xff\xd5\xe6\x09\x20\xb0\x03\xf0\xc9\xad\xc2\xad\x49\ +\xb4\xc4\x9c\x40\x93\x34\x28\xf6\xff\x02\xe0\x30\x2c\xca\x90\xd6\ +\xbb\x27\x01\x7e\x0c\x40\x29\x66\x12\x04\x59\x13\xe0\x10\xf1\xca\ +\x61\x9c\x65\x49\x55\x9f\x15\xe2\xd6\x65\x19\xd1\x04\x1c\x03\x73\ +\x1a\x71\xc0\x18\x70\x9c\x5a\x07\x53\xb8\x21\x9e\x2e\x50\x06\x1b\ +\xe4\x75\x19\x44\x30\x68\x2c\xa0\x0d\xaa\x0e\xd5\x2e\x10\x0d\xf5\ +\x75\xd4\xb3\xa8\x68\xbd\x16\x69\x35\x02\x3b\xc0\xd0\x61\xc3\x3e\ +\x90\x66\x4b\x6b\x54\xa3\xd4\x2e\x1e\xd0\x6c\x73\x02\x2a\x65\x78\ +\xf1\x60\xcb\xcb\x66\x18\xf1\xa0\x0a\x88\xac\x04\xbd\xb5\x54\xd0\ +\x91\xd4\xe5\x44\x3c\x7e\x11\x9d\xef\x94\xe4\x8d\x53\x2d\x95\x93\ +\x63\x6b\x59\x93\x14\x1a\xfb\xd8\x70\xdb\xa5\xe4\xea\x78\x08\x1a\ +\x36\xfc\xb0\xd9\x92\x08\x80\xc0\x0e\x70\xf2\xc8\x53\x66\xf6\xe8\ +\xb1\xd7\x4e\xe7\x26\x88\x6e\x38\x6e\x07\xc7\x82\x4c\x78\x70\x02\ +\xd8\xe4\x24\xe0\xd5\xcd\x72\xa3\x23\x16\xd4\x58\x67\x9d\xb4\xaa\ +\x46\x66\x82\x72\x5b\x34\x06\x30\xd1\x34\xca\x32\xe5\xb1\x74\x53\ +\x93\x2e\x7f\x48\x5d\xde\x32\x1c\xd0\x9d\x7b\x57\x0d\x36\xd0\x93\ +\x43\x4e\xda\x66\xca\x73\x90\x59\x7e\x0c\xa0\x1d\x52\x44\x82\xd4\ +\x06\x65\x70\x3d\x7a\xc2\xe2\x03\x94\x51\xb9\xea\xf8\xe8\x45\x78\ +\x65\xd5\x34\x72\xd4\xe8\xe9\xc2\x0e\x80\xc0\x0e\xc0\x63\x6c\x09\ +\xcf\x8c\xa7\x54\xe9\x25\x0b\x96\x7d\xbc\x2c\xa4\xd5\xab\x62\xff\ +\xa0\x72\xd5\xca\x95\xec\x20\xa2\x2d\x9c\x83\x9c\x34\x1c\x66\xe9\ +\xd7\xb1\x9f\xe1\x8f\x32\x58\x16\x61\x36\x6f\x94\x05\x63\x6c\xdb\ +\xba\x95\x36\x6c\xf0\x7f\x38\x35\x14\xb3\x76\xcd\x6a\x36\xa8\x9a\ +\x61\xeb\x82\x52\x76\xc5\xf2\xd8\x3f\xd7\x5e\xfa\xf5\xd7\x54\xcf\ +\xb3\x70\x51\x32\xca\x48\xfb\xd2\x69\xcb\x96\x2d\x54\xb6\xdd\xff\ +\x57\xc6\xdf\x7f\xff\x3d\x15\xaf\x2b\xb6\x9c\x87\x99\x1c\xd0\x95\ +\xaf\xfc\xf6\x5b\x25\xe4\x83\xa5\x4b\xbf\x96\xa1\x45\x84\xa5\x0c\ +\xd7\xc5\xc7\xd8\xb4\x61\xa3\x2c\x53\xfd\xb0\x65\xcb\x66\x09\xc6\ +\x89\xab\xaa\xaa\xe9\xe8\x63\x8e\x79\xef\xa0\x83\x86\x2c\x16\x46\ +\x00\xf8\xae\x02\x32\xf4\x6c\x3b\x1e\x2a\x78\x96\xbb\x79\xd3\xc6\ +\x3e\x63\xcf\x3d\xe7\xcb\xd2\xd2\x6d\x85\x58\x9a\xe0\xa5\xd1\x03\ +\x06\xec\x4b\x13\x2e\xbe\x84\xba\x75\xef\x2e\x0a\xc1\xcc\x1d\xbd\ +\xc4\x82\xf9\xf3\xe9\xed\xb7\xde\x90\x49\x93\x80\xf9\xa8\xc5\x28\ +\x6d\xec\xb8\x71\x74\xe8\xd0\x61\xce\x95\x86\x72\x58\x92\xbd\x30\ +\xe5\x79\x2a\xdd\xb6\x8d\x15\xcc\xe5\xb8\x80\x69\x19\xea\x1a\x7c\ +\xe0\x10\x3a\xff\x82\xb1\x3c\x39\x2a\x90\xab\x1b\x99\x98\x95\xcf\ +\xf9\x60\x36\x7d\x30\xeb\xfd\x88\xef\x21\x90\x87\x31\x14\x86\x1a\ +\x37\x7e\x82\xcc\xb6\xcd\xb1\x40\x6c\x64\x67\x7a\xe1\xf9\xe7\xe9\ +\xfb\x5d\xdf\x2b\x05\x1b\xb5\x70\x5e\x2d\x2f\x03\x0f\x3b\xfc\x08\ +\x3a\x73\xcc\x59\x72\x2f\x83\x27\x3b\xd2\xbe\x9a\xda\x6a\x7a\xf7\ +\x9d\x77\xe8\x13\x3e\x37\x9c\x3f\x0a\x49\x31\xde\xa9\xab\x33\x87\ +\x2e\xbe\xe4\x32\xda\xa7\xbf\x3b\xc9\x45\xfe\x9a\x55\xab\xf8\xbc\ +\x9e\x93\xe3\xe2\x7c\x55\x19\x55\x61\x2d\x9f\xd7\x09\x3f\x3c\x91\ +\x46\x8d\x3e\xd5\x79\x59\x34\xea\xaa\xac\xdc\x45\xaf\xbd\xf2\x0a\ +\x7d\xf1\xc5\x62\xe1\x43\xa7\x5c\xb6\xe1\x85\xa9\x2f\x1f\xcb\x43\ +\xc0\x67\xf9\xb8\x17\x91\x00\x1a\x74\x3d\x06\x81\x1d\xa0\x9c\x3d\ +\x1f\x33\xe3\xa9\x2f\xfe\xf3\xa2\x9b\x6f\xb8\xfe\x1f\xa0\xd1\x95\ +\xe3\xd1\x2d\x58\x37\x9b\x7f\xd0\xa0\xf1\xa8\x02\x5d\x5b\x6e\x5e\ +\x9e\xa4\xed\xa3\xab\xfc\x66\xf6\x66\x7b\x22\xcb\x12\x10\x62\x7e\ +\x76\x76\x8e\x76\x1a\x4f\xc3\xb9\x1c\x14\x88\x31\x50\xdd\x74\x12\ +\xae\x1c\xab\x13\x5f\xb5\x39\xf6\x13\xc1\x74\x36\x22\x38\x81\xaa\ +\x4b\xd7\xa1\x81\x72\xb8\xa1\x83\x2f\xb7\xa4\x26\xab\x3a\x1c\x1e\ +\x57\x65\x7d\x7d\x83\xd4\x6b\x32\x55\x5d\x19\x5c\x2e\x5b\x68\x2f\ +\xe0\x04\x52\x17\xca\x58\x07\x85\x2c\xf4\x25\xc6\xb7\xca\x19\x91\ +\xea\xea\x2a\x31\xb0\xd1\x8d\xb0\x79\x22\x9c\x91\x91\xc9\xfa\xc8\ +\x92\x61\xb3\xa2\x62\x27\xdd\x7e\xd7\xdd\xf7\xdf\x7e\xe7\x3d\x13\ +\xe1\x1c\x5d\x0b\x12\x7b\x68\x56\x5b\x39\x40\x84\xc0\x83\x0f\x4e\ +\x7c\xf0\xf7\x8f\x3d\x7a\x0f\x2f\x47\xf8\xa4\xf4\xb8\xc7\x12\x46\ +\x48\x62\x39\xa6\x62\x2a\xbe\x4d\x5b\x60\x39\x97\xe7\x0a\x44\xb8\ +\x8d\xcb\xf6\x81\x5d\xc6\x0f\xe0\xea\x2b\xd5\x82\x92\x55\x79\x5e\ +\x38\x1c\x21\xa2\xf3\x01\x6f\x96\x53\x83\x95\xa1\x48\x4b\x88\xe1\ +\x66\xbb\xbd\x87\xde\xb9\xc6\xb7\x76\xe0\x55\x54\x54\xd0\x8f\x27\ +\x4c\xf8\x67\xf7\xc2\xbd\x2e\x79\xe8\xc1\x07\x95\x90\x82\x4d\xfb\ +\x22\xa8\x03\x80\x61\x33\x4d\xda\xf0\xd2\xee\xbc\xf3\xf6\xfb\xfe\ +\xfe\xcc\x5f\xff\x17\x5d\x2c\x6e\xda\x48\x96\xfa\x38\x50\x57\x8f\ +\x50\x56\x9e\x4d\x6b\x48\xc2\xe3\x08\x56\x04\x78\x1d\xc2\x8a\xe2\ +\xa0\x65\x09\x85\xf8\x7a\x74\x72\x2d\xb1\x08\x97\xf2\x08\x38\x7b\ +\xaf\x88\xde\xd9\xb4\xec\x2d\x9b\xd8\x79\x18\xde\xd0\x13\x9d\x7d\ +\xee\x79\xcf\xe5\xe6\x15\x5c\x37\x79\xd2\x24\xf3\xa0\x24\x48\x98\ +\x60\xe0\x4d\x0b\x5a\xeb\x00\x20\x4c\x40\x9f\x6e\xc7\x5e\x3a\xed\ +\x8e\x3b\x6e\x3f\xf7\xfd\xf7\xfe\x35\x71\xc3\x86\xf5\x7d\x3b\xb3\ +\x13\xc0\x19\xc4\x50\xea\xe3\xc0\x75\x04\xc0\xce\xb7\x69\x0b\x11\ +\xbd\x02\xa0\x53\x1e\x41\xaf\x94\x00\x2c\x9c\xa2\x4f\x56\x8b\x88\ +\x56\x8d\x20\xc2\xd8\x80\x93\x74\xf9\x42\x79\x74\xab\x78\x6a\x67\ +\xd3\x06\xb1\x0c\x8f\xe1\x00\x73\x9e\xc2\xc2\xc2\x1d\x67\x9e\x75\ +\xce\xaf\x1f\x79\xe4\xd1\xa7\x74\xae\x09\xb8\x79\x60\x6e\x20\x18\ +\xda\xce\x47\x10\xb4\xc6\x01\xb0\x43\x40\x9f\x0e\x43\x23\xb6\x03\ +\x78\x26\x18\xd9\xf4\xd3\xcf\x38\x7d\xcf\xbc\xdc\x9c\x4b\x57\x2c\ +\x5f\x76\x7e\x69\x69\x69\x5f\xfc\xc1\x02\x93\x2a\x8c\x77\x66\x82\ +\x07\xc4\x75\x02\xec\xed\x6c\x40\xd2\x7e\x26\x66\x9e\x87\x89\x33\ +\xd2\x47\x91\x7d\x78\x28\x83\x79\x8f\xa6\x54\x17\xa9\x3f\x95\xe2\ +\x7d\x24\xdb\xf2\x85\x96\x8d\x8f\x79\x8a\xba\xa9\xd6\x40\x9d\x78\ +\x48\xed\x5e\x58\xb8\x75\xd0\xa0\xfd\x67\x14\x74\xe9\xfa\xb7\x29\ +\x53\xa6\x14\x43\x84\x03\x0a\x20\x18\x83\x63\x49\x61\x62\x3b\xd8\ +\xb2\x09\x3b\x00\xce\x15\xc1\x18\x1e\x0b\x6e\xcc\xc4\x4c\x88\xe5\ +\x08\x08\x52\xb6\x5f\xbf\x7e\xf9\xc7\x1e\x7b\xcc\xe1\x3c\xa9\x3a\ +\x64\xf3\xe6\xcd\xfb\xd7\xd6\x56\xef\xcd\xcb\x96\x1c\xce\x54\x15\ +\x32\xa1\x3e\xde\x84\xcb\x32\x70\xcc\x6e\xf1\x6c\x88\x0b\xc4\xc8\ +\x73\xd1\xa2\x80\x07\xd1\x7a\x89\x00\x67\xb3\x29\xfd\x85\x34\x37\ +\xa2\xa7\x70\xc8\x68\x07\xe0\xbd\x23\xca\x47\x4c\xcb\xce\xc9\xae\ +\xcd\xcc\xca\xdc\xdc\xb3\xa8\xd7\xca\xa6\xc6\xa6\xaf\x57\xae\x5a\ +\xf5\xd9\x97\x4b\xbe\xc4\x23\xce\x20\x65\x0c\x6e\xd3\xc6\xd8\x0d\ +\x3a\xe0\x6f\x4d\x08\x26\x0d\x59\xa9\x81\x1d\x40\xd7\xa4\xd0\x92\ +\x03\xd8\xc6\xc7\x3a\x07\x83\x3b\x68\xf0\x4c\xf0\x3a\x80\xe3\x04\ +\x2d\x04\x20\x56\x0c\xf8\xf1\x00\x6f\xda\x8b\x58\xf9\x2d\x95\xf3\ +\x22\x5a\x31\x0a\xb1\xf8\x06\xde\x7c\x93\xb6\xf9\x36\xcf\xcb\x6f\ +\x29\x18\xa3\x7b\x8d\x6f\x0c\x8e\x18\x73\x03\x13\xc0\x43\xbe\xc0\ +\xeb\x00\x30\x56\x22\xb0\x95\x07\xba\xb5\x21\x51\xa7\x40\x88\xe7\ +\x44\x7e\x7c\x23\x1f\xaf\x5c\x5b\x86\xa0\x75\xc5\x92\x6f\x2d\xdf\ +\x2f\x00\x5e\xda\x2f\x8e\x42\x22\x3d\x00\x82\xe9\xfa\x4d\x6f\x60\ +\xae\x7e\x7b\x08\x30\xf2\x76\xc3\x81\x58\x27\x02\x78\x63\xc0\x2b\ +\x03\xd8\x34\xd0\x52\xda\x8b\x96\xf2\x63\x21\x5a\x39\x2e\xfc\xf2\ +\xbc\x3c\x3b\x0d\xda\x04\x83\x58\x69\x3b\xe0\x2a\x07\x0c\x6d\x82\ +\x9d\xf6\xeb\xfe\xed\x21\xc0\xc8\xa5\x25\x3a\x04\x20\xc2\xce\x18\ +\xd7\x38\x82\x31\xba\x1d\x8c\x9c\x1d\x7b\x69\x6f\x00\xbc\xb4\x89\ +\x6d\x3e\xe0\x95\x31\xf0\xa6\x81\x44\x64\x82\xc0\xab\xa4\x68\xa5\ +\xc5\x96\xb1\xf9\xa0\x4d\x00\xec\xd8\xa6\x61\x2c\xc0\xf0\x0d\xcf\ +\x4b\x1b\xc3\x22\x98\xa1\xc0\x74\xf9\x76\x30\xe5\x02\x2f\x03\x8d\ +\x23\x98\x60\x78\x76\xdc\x9a\x00\xd8\x34\xe0\xe5\x7b\xf3\xbc\x69\ +\x3f\x78\xe5\x6c\xc4\xe2\xc7\x42\xb4\x62\x5c\x5e\xbc\x3c\x03\xa4\ +\x6d\x9e\x49\x1b\x5e\xbc\xd8\x18\x18\x40\x1c\x2f\xd8\xce\x60\x62\ +\xe3\x10\xb6\x9c\xa0\xb5\x0e\x00\x98\x84\x51\xae\x1d\x00\x3b\xf6\ +\xf2\x6d\xda\xc4\x86\x06\x12\xc9\xb7\xd3\x80\x37\xdf\x86\x37\x6d\ +\x23\x5e\x9e\x1f\xa2\x15\xa3\xe0\xc7\xb7\x79\x7e\x74\xa2\x31\x00\ +\xda\x2f\xdf\x4b\xb7\x94\x67\xf3\x1c\x04\x71\x00\x20\x51\x45\x1b\ +\xbe\x37\xb6\xe1\x97\x17\x4f\x0e\xf0\x2b\xe3\x87\x78\xf9\x2d\x95\ +\xf5\x22\x5a\x31\x0a\xb1\xf8\x06\x76\x7e\x2c\xda\xc0\x9b\xef\x27\ +\x03\x18\xbe\x37\xf6\xc2\xe6\xfb\xca\x04\x75\x80\x44\x60\x0a\xe1\ +\x80\xb1\x0e\xd0\x5a\xbe\x8d\xb6\x92\x09\x0b\x5f\xc5\xfa\x20\x11\ +\xb9\x58\x32\xf1\xf8\x38\xc7\x44\xdb\x10\x85\xf6\x74\x80\x30\xe8\ +\xf0\x0a\xff\x4b\x10\xd8\x90\x41\x91\x90\x03\xa4\x90\x3c\xc0\x0c\ +\x3e\x85\x24\x46\xca\x01\x92\x1c\x29\x07\x48\x72\xa4\x1c\x20\xc9\ +\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x72\xa4\x1c\x20\ +\xc9\x91\x72\x80\x24\x47\xca\x01\x92\x1c\x29\x07\x48\x6a\x10\xfd\ +\x1f\xc7\xc9\xb8\x91\x66\xc8\x02\x22\x00\x00\x00\x00\x49\x45\x4e\ +\x44\xae\x42\x60\x82\ +\x00\x00\x1f\x16\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x0e\xc2\x00\x00\x0e\xc2\x01\x15\x28\ +\x4a\x80\x00\x00\x1e\xab\x49\x44\x41\x54\x78\x5e\xed\x9b\x49\x90\ +\x64\xd7\x75\x9e\x4f\xce\xf3\x54\x99\x59\x99\x35\x74\x55\x4f\xe8\ +\x19\x00\x01\xb0\x31\xb4\x6c\x02\x16\x85\x16\x6c\x85\xb4\xd3\x4a\ +\x0e\xda\x1b\x71\xe1\xf0\xc4\x85\x6d\xda\x0b\x63\xe5\xf0\x82\xc6\ +\xca\x2b\xaf\x1c\x1e\xc2\x11\x0e\x30\x6c\x53\x96\x2c\x3b\xcc\x20\ +\xd5\x04\x21\x00\xc4\xd0\xdd\x40\xa3\xa7\xea\xa9\xe6\x21\xab\x2a\ +\x2b\xe7\x97\xb3\xbf\xff\x16\x68\x8b\x44\xa2\x49\x84\x37\x5a\xe0\ +\x22\x12\x55\x95\xf9\xf2\xbd\x7b\xcf\xf9\xcf\x7f\xfe\xff\xbe\xd7\ +\xf6\xd5\xf8\x6a\x7c\x35\xbe\x1a\x5f\x66\x8c\x46\xa3\xd8\x78\x3c\ +\x0e\x7d\xf6\xe7\x5f\x8a\xc1\x7c\xc2\xbc\xa2\x9f\xfd\xf9\xa5\x86\ +\xef\xb3\x9f\xbf\x6a\xf8\xfe\xe8\xdf\xbc\x1e\x1b\x87\x33\x7f\xb7\ +\xdd\x6a\x65\xc3\xe1\xb0\xb5\x3d\xcf\x1e\x54\xb6\xed\x5c\x69\xc6\ +\x22\xb1\x88\x0d\xc7\x43\x0b\xf8\xfc\x56\xad\xd6\x2d\x97\xcb\x9b\ +\xdf\xef\xb7\x56\xab\x65\xc1\x60\xd0\xfc\xc1\x10\x17\x1a\x70\x9a\ +\xb1\xb5\xda\x6d\xeb\x79\x3d\xf3\xdb\xc8\xe2\xf1\xa4\xbd\x7d\xe3\ +\xae\xdd\x5c\xa9\xd8\x33\x27\xe7\xed\xe5\x8b\x4f\x59\xaf\x37\xb0\ +\xee\xb0\x6f\x31\xce\x69\x23\xbf\xed\xec\x55\xed\x4f\xde\x7e\xdf\ +\x5a\x5d\xcf\x2e\xbf\x74\xd1\xce\x1d\x3f\x66\x57\x6f\x2c\xd9\x5b\ +\x1f\x5e\x35\xaf\xd7\x33\x2e\x64\xc1\x38\x67\xeb\x8e\x7c\xfe\x40\ +\xf8\xa0\xba\xbd\xf7\xaf\x3f\xfc\xf0\xc3\x8e\xbb\xd8\xaf\x31\x7e\ +\x65\x00\xfe\xf3\x1b\xdf\x89\x8d\x62\x85\xaf\x77\x7b\x9d\xef\x25\ +\x13\x89\x17\x6a\x8d\x96\xa5\x93\x71\xeb\x30\xa1\xe5\xfd\x7d\x3b\ +\xb3\x70\xcc\xe2\x81\x80\x8d\xfa\x3d\xd0\x31\xb4\x7a\xcb\xb3\x04\ +\x0b\xf3\xfb\x7c\x36\x1c\x0c\xdc\x7b\x23\x2e\x33\x1e\x8f\x2c\x1a\ +\x09\x5b\x80\x09\xfb\x78\xf9\xfd\x84\xa4\xdb\xb5\x1f\x7d\x78\xd3\ +\xae\xdd\x5b\xb5\xe7\xce\x1c\xb5\x57\x5f\x7c\x86\x63\xcd\x9a\x1d\ +\xcf\x7c\x01\xbf\x0d\x86\x63\x1b\x71\x8e\xef\xff\xf0\xa7\x56\xeb\ +\x74\xec\x6b\x67\x4e\xda\xcb\xcf\x3d\x63\x1f\x7d\xba\x64\x7f\xf6\ +\xde\x07\x42\x23\xc7\xf9\x2c\x1c\x0f\x59\x24\x14\x24\xf8\x6d\x1b\ +\x8f\xc6\x6f\xa7\x92\xe1\x7f\x90\x89\x17\x3e\x79\xf3\xcd\x37\x89\ +\xd0\xe3\x47\xe0\xb3\x9f\x13\xc7\xdb\xff\xeb\xdf\x4f\xf7\x7d\xf1\ +\x3f\xec\xf7\xbb\xff\x2a\xe4\x0f\x9d\xf1\xfa\x3d\x5f\x36\x9d\x64\ +\x62\x23\x5b\x25\x33\x8f\x76\x2b\x36\x24\xb3\x89\x60\xc4\x06\xbd\ +\x3e\x21\x67\x71\x64\x3c\xc4\x64\x84\x80\x00\x8b\xd0\xef\x42\xcc\ +\x88\x80\xf8\x08\x54\x80\x9f\x44\xc3\xc6\xc3\xa1\x79\x5e\xd7\x02\ +\xc1\xb0\xad\x6e\xef\x58\x07\x54\x3c\x7d\xea\x98\x0b\x8e\x71\x4c\ +\xbd\xd5\xb6\x54\x22\x6e\x89\x44\x8c\xeb\x0d\x6d\x6d\x7b\xcf\x86\ +\x04\x73\xb1\x3c\x6d\xd1\x60\xc0\x3e\xbc\x79\xdf\xc6\x1c\xea\xe7\ +\x1a\x9c\xcd\x62\xa1\xa8\xf5\x41\x4e\x34\x16\x3a\x12\xf2\x07\xfe\ +\x6a\xaf\xdf\xd9\x3b\xb6\x78\xf2\x01\xa3\xff\xd9\x72\x26\x0e\x4e\ +\x31\x79\xfc\xf8\xbf\xfe\xdb\xec\xb8\xef\xfb\x87\xf1\x44\xe2\xbb\ +\x60\x6b\xae\xdd\xed\xb2\x02\x9f\x83\x74\xb7\xdb\xb3\x26\x99\xae\ +\xed\xb7\x2c\x36\xe4\x60\x32\xd1\x17\xc8\x29\x01\x8e\x65\xa2\x23\ +\x97\x1d\x4d\x6e\x34\x1a\x5b\x8f\x2c\xf6\x07\x7d\xe0\xed\xd9\xfa\ +\xce\x8e\xfb\x5d\x41\x50\x2c\x04\xe3\x62\x26\xed\x02\xa8\x85\x36\ +\x9a\xad\xc3\xe0\x05\x09\x1e\xdf\x0f\x12\xb4\x73\x27\x16\xed\xe9\ +\x13\x47\xb9\xd0\x98\xc0\xb4\xdc\x39\xf5\x5d\xae\x66\xfe\x31\x48\ +\xeb\x69\x12\x01\xf3\x01\x7a\x90\xe7\xf3\x3a\xbd\xb3\xad\x76\xef\ +\x5f\x8c\x7c\x83\x6f\xbd\xf8\xe2\x8b\x31\xad\xe7\x8b\xc6\x44\x04\ +\xbc\xfe\xfa\xeb\xc1\xf9\xa9\xe8\x3f\x66\x22\x7f\xbf\xd1\x69\xe7\ +\xb4\x40\x65\x32\x16\x0d\xbb\x9f\xcc\x9d\x8c\x79\xae\x56\xf3\xf1\ +\x94\xe5\x32\x09\x3e\x8b\x90\x71\x26\x03\x86\x59\x07\x01\x6a\x5a\ +\x8a\x52\x21\x6a\x16\x08\x85\xad\x37\x1c\xf0\x19\x7f\x11\xa0\x6e\ +\x1f\xd4\xc4\xe2\x2c\xd0\x67\xdb\x7b\xfb\xb6\x53\x03\xba\x5c\x77\ +\x6e\xa6\xc8\xc2\x83\x7c\x7f\x68\xbd\x7e\xdf\xe2\xb1\x28\x0b\xf5\ +\x39\x2e\x51\xa6\x5a\x94\xcc\x88\x8b\x0f\x07\x63\xbb\xfd\x68\xd5\ +\x05\x41\xc3\x1f\xf2\x5b\xbf\x4f\xa9\x81\x90\x46\xbd\xab\xf7\x7d\ +\xb1\x48\x28\xdb\x1f\x0c\x9f\xf7\x85\x7d\xdd\x17\xbe\xfe\xc2\xcf\ +\x6e\xde\xbc\x39\x91\x13\x26\x22\xe0\xe2\x62\xec\xf7\x2a\x95\xfd\ +\x7f\xb2\x5d\xa9\xa4\x43\xbe\x80\xc5\x80\x70\x84\x45\x04\xfc\x41\ +\x26\xd3\x71\x13\x9c\x2f\x16\xed\xe9\x85\x45\x9b\x82\xf0\xe0\x06\ +\x0b\x13\x98\x68\x38\xc4\xe4\xfa\xd6\x1f\x0d\x2c\x96\x48\x81\x80\ +\x80\x85\x63\x61\x16\xdc\xe3\xfb\x21\xab\x77\x5a\xc0\x9a\x60\xc5\ +\x13\xd6\x04\x15\x95\x86\x47\x46\x3b\xf6\xea\xd7\xcf\xd8\x37\x9f\ +\x3f\x6f\xd9\x68\xc0\xc6\x03\x0f\x04\x04\xac\xb2\xbb\x07\xd1\x76\ +\x6d\xc0\x71\x7e\xf8\x23\x9b\x8a\xd9\x5c\x36\x6b\x01\xb2\xdd\xaa\ +\xd5\x5d\x60\x15\x9c\x40\x18\x3e\x01\x2d\x5d\xd0\x35\x24\xfa\xa9\ +\x74\xc4\x52\x99\x28\x41\xf1\x59\x36\x1d\x2b\xfa\x86\xf6\x8f\x16\ +\x16\x16\xbe\xb0\x43\x7c\x2e\x00\xb4\x93\x38\xe0\x3d\x0e\x04\xa3\ +\x51\x16\xbe\xbe\xb5\x65\x9b\xfb\x55\xdb\xd8\xde\x36\xd0\x60\xb5\ +\x66\x17\x48\x1f\x42\x1c\xbc\xb9\x85\xf5\xc9\x88\xb2\xd2\x65\xc2\ +\x7e\x58\xc1\x47\x96\xa2\x2c\x7c\x08\x54\x95\x8e\x41\xdf\x03\xca\ +\x3e\x8b\x05\x40\x0f\x59\xd2\x77\x62\x91\xa8\xe5\xf3\x39\x02\x47\ +\x07\x19\xf4\x6c\x3a\x9b\xb4\x60\x88\x60\x07\x7d\x76\x50\xdd\x83\ +\x64\xfb\xb6\xbc\xb2\x61\xad\xa6\xc7\xb1\x11\x38\x03\xc2\xe3\x9a\ +\xc9\x64\x4c\x57\x60\xd1\x41\x37\x87\x51\x9f\x6e\x12\x8c\xda\xb1\ +\x99\x92\x08\xd0\x3c\xbe\xc7\xc7\x90\x27\xe5\x52\xef\x80\xd8\x40\ +\x64\x79\x79\x19\xe0\x8c\xe3\x9f\x2d\xf1\x17\xc6\x24\x04\x8c\x5a\ +\x30\xfd\x10\xc8\x06\x55\x54\xe3\xbe\x35\xbd\x86\xd5\x61\xfd\x46\ +\xb3\xed\x88\x48\x10\x1e\xb3\xb0\xde\x00\x22\x23\xf2\xb5\x7a\x13\ +\x08\x0e\xc8\x16\x93\x84\x07\x44\x4b\x9a\x1c\x24\x6e\xed\x76\xc7\ +\xd5\xb1\xa0\xaf\x92\xe8\x72\x9e\x16\x81\x6c\xf3\x1a\x50\x42\xa5\ +\x42\x9a\xbf\x09\x6a\xaf\xc3\xab\x47\x10\x42\x96\x8c\x85\x28\x8f\ +\x90\x45\x29\xaf\x28\xf0\x6e\x72\x0e\x5d\x6b\x7e\x6e\xd6\x8e\x2f\ +\x1c\xb1\x7c\x2e\x45\x40\x40\x59\x34\x64\x8b\x33\xd3\x76\xac\x54\ +\xb2\x48\x38\xea\xba\x46\xdf\x83\x6f\x5a\x74\x1f\x7e\x57\xa7\x21\ +\x2a\x56\xa9\x54\x58\x3f\x7d\x7a\xc2\xf8\x5c\x00\xc4\x21\xe1\x68\ +\xcc\x42\x2c\xb0\x59\xaf\x5a\x0c\x42\x2a\x26\x32\x56\x86\xa8\xb2\ +\x09\xa0\xa5\xa0\xf8\x46\x90\x61\xc0\xe2\x64\x66\x24\xc8\xf3\xea\ +\x32\xf9\x1e\xd1\xf7\x51\x26\x09\xd8\xdb\x05\x84\xac\x89\x30\xab\ +\x07\x4d\xfb\xf0\xd3\xbb\xf6\xd6\xd5\x1b\x0e\xde\xef\x5d\xbf\x69\ +\x3f\xf9\xe8\xba\xbd\xfd\xc1\x75\x17\x90\x01\xc1\xda\x27\xd3\x6b\ +\x3b\x55\xab\xd6\x5b\x16\xa6\x33\x28\x98\x0f\x37\xb6\xed\x1d\x7a\ +\xfe\xf2\xe6\xae\x2d\xad\x6e\x51\x5a\x90\x2d\x81\xb8\x7a\xeb\x3e\ +\xc9\xf1\x59\x02\x4e\x52\x6b\x55\x49\x7a\xdd\x81\xd3\x21\xe2\xa8\ +\x68\x24\x64\x09\x5e\xd1\x70\x50\x58\x71\xeb\x82\xcf\xba\xee\x97\ +\x5f\x1a\x13\x49\xf0\xb5\x57\x5e\xba\xe4\x0b\xfa\x2f\x77\xbc\x0e\ +\x17\xf5\xb9\x8b\x28\xda\x3a\x99\xa2\x1a\x16\xec\x85\x02\x26\xb4\ +\xb5\x7f\x60\x19\x16\x7c\xe0\xd8\xdb\x20\x2f\x32\xc0\xab\x07\x61\ +\xc5\x98\x40\x1f\x76\xdf\x42\x2f\x5c\x5d\x7a\x64\xdb\xd5\x03\x9b\ +\xc9\x67\x6d\x69\x79\xd3\xb6\x20\xbf\xed\xdd\x03\xdb\xa9\xd6\x6c\ +\x75\xb7\x66\xf7\x37\x2a\x70\x42\x43\x44\xef\xb8\xe4\xdd\x4f\x96\ +\xec\xe6\x83\x55\x5b\xdd\xd9\x25\x20\x7e\xab\x1c\xd4\xe0\x1b\xf1\ +\xf1\xd8\xe9\x90\xc5\xf2\x94\x9d\x3e\x7a\xc4\x0a\xb9\xac\xcd\x97\ +\x8a\x76\x00\x0a\x25\x9a\x7a\x04\x43\xdf\xd7\x71\x7a\x31\x5f\x6f\ +\x30\x18\xbf\x41\x19\x48\x89\x7d\x6e\x4c\x2a\x01\x45\xcb\x41\xd9\ +\x63\xf1\x1d\xd8\x98\x60\xbb\xba\x16\xfc\xd7\xb6\x2b\xf6\x60\x7d\ +\xc7\x95\xc1\x3e\xec\x9c\xa0\xd6\x35\xc9\x7c\x26\x65\xe9\x54\x92\ +\xbf\x23\xd6\x67\xf1\x61\x60\xaf\x20\xfc\xf0\xa3\x8f\xed\x5d\x7a\ +\xf6\x01\x65\xd5\xf5\xfa\xb6\x44\x5d\xfb\x20\xd6\x1e\xac\xad\x32\ +\xaa\x35\x3b\xbc\xda\xe6\xef\x8d\xad\x41\x6b\xd5\xe2\x88\xab\x0b\ +\xb4\x6a\x59\x19\x7f\x40\x70\x58\x04\x0b\xdc\x27\x70\x55\x3b\x42\ +\x29\x9c\x39\x79\xdc\x66\x8b\x79\x2b\xe5\x33\x56\x98\x4a\x5b\x88\ +\x20\xe5\x52\x09\xd7\xa1\xa6\xd2\x69\x7b\xe9\x6b\x90\x6a\x26\x69\ +\xa1\x68\xd0\x4c\x1d\xf4\x0b\xc6\xc4\x00\x6c\xd5\x6a\xd6\xa2\xcd\ +\x05\x81\x73\x8c\xda\x12\x51\x0d\x86\xcc\x26\x10\xb6\x8f\x96\x56\ +\xc8\x68\x95\x09\x79\x96\x4f\x41\x66\x51\x68\x8f\x5a\x6e\xb4\x3d\ +\xeb\x50\x06\x3e\x26\x9e\x62\x22\x22\xbd\x0e\xd9\x4f\x52\x4e\x52\ +\x85\x52\x80\x0a\xec\xc8\x3f\xb6\xe3\xb3\x05\x87\xa2\x10\xf5\x1d\ +\xa4\xd7\x0b\x39\x7e\xde\xcf\x86\x09\x1e\x81\x49\xa7\x53\x76\xf1\ +\xdc\x71\x4b\x49\x39\x32\x9f\x29\x02\xfb\xb5\xd3\xc7\xc9\x34\x12\ +\x9b\x37\xc4\x2f\x85\x99\x05\x1b\x87\x13\x56\x6b\xb4\xe1\x90\x1e\ +\x1a\xc4\x67\x33\x85\x0c\x9c\x01\xfc\xe3\x31\x3b\x75\x64\xd6\xca\ +\x53\x19\xa7\x51\xec\xd1\xe1\xba\x26\x8d\x89\x25\xf0\xbb\xbf\x75\ +\xe9\xd2\xdd\x8d\x8d\xcb\x12\x28\x52\x62\x6a\x39\x8a\x95\x60\xb8\ +\xba\xb5\x63\xe7\x16\x4b\x96\x4d\x06\x9d\x70\x09\x12\xf9\x30\x2d\ +\xf2\xde\xda\x8e\xa5\xb9\x70\x3c\x1a\x75\xac\x2d\x04\xed\xd7\x1a\ +\x76\x64\x3a\xcf\xfb\x71\x9b\x2b\x66\x60\xea\xa2\x05\x11\x2e\x0b\ +\xa5\x69\x6a\xb6\xe3\xfa\xba\x48\x2f\x8a\x94\x55\x2a\x02\x04\xf8\ +\xdc\x13\x47\x39\x37\x0a\x90\xfa\x56\xc9\xbc\xfc\xec\x79\xfb\x6b\ +\x2f\x3c\xc5\x7b\x09\xcb\xf0\x2a\xe6\xd2\x76\x1f\x14\x45\x22\x71\ +\x5a\x1d\xf5\x4f\xc6\x9b\x10\x6a\xab\xde\x20\xb0\x33\xb6\x50\xce\ +\xdb\x5c\x21\xeb\x4a\xf2\xd1\x56\xc5\xda\xa8\xaf\xfe\xcc\xe8\x8d\ +\xe5\xeb\x93\x4b\x60\x62\x00\x9e\xba\x70\xfa\xd2\x4e\xad\x79\x59\ +\xb5\x1f\x27\x2b\x41\x52\x14\x80\x5c\x6a\x9c\x14\x3e\xb7\x02\x3d\ +\x39\x25\x42\x04\x6f\x3e\x88\x2e\xce\x71\x6b\x95\xaa\xa5\xe1\x02\ +\xd5\x5f\x90\x76\xa7\xda\x57\x41\xcb\x07\x84\x79\xaf\x5c\x98\x02\ +\xae\x53\xb4\xb1\x84\xc5\x59\xb4\xd4\xe2\x0c\xef\xbd\x72\xf1\x69\ +\xab\x53\x02\x51\x16\xf3\x57\x9e\xbd\x60\x19\xb2\x2f\x74\x28\xe8\ +\x27\x66\x0a\x36\x53\x2a\x1c\x22\x87\x7a\x96\x48\x0a\x73\xad\x23\ +\xe5\x22\x7a\xa4\xce\xf7\x0e\x78\x9f\x52\x62\x0e\x3a\x86\x58\xc0\ +\x13\x69\xce\x15\xb4\x4f\xef\xaf\x58\x13\x02\x9e\x2d\x64\xbd\xf3\ +\xc3\xfc\x1b\x57\xae\x5f\xff\xf5\x03\x30\x7d\x6c\xf6\x52\xdb\xeb\ +\x39\x04\x14\xa8\x6d\xd7\xc6\xc8\xa8\x7a\xb8\x20\xde\x43\xd8\x24\ +\xc2\x01\x57\x3f\x63\x67\x58\xe8\x04\xfc\x94\x3e\x48\xc1\x01\x5d\ +\xfe\x8e\x52\x3a\x87\x68\x80\x40\xe9\xf9\x2a\x68\xc7\xd0\x2c\x42\ +\xe7\x09\xf1\x53\x5e\x41\x59\x15\x89\x0a\xbe\xaa\x7b\xf5\xf7\x80\ +\xae\xe7\x82\xc7\x04\x23\x31\x54\x27\x48\x21\x11\x71\x90\x14\xa4\ +\x06\x46\x20\x4f\x32\xdb\x63\x81\x29\x50\x27\x79\x2c\x5f\x11\xe4\ +\x5a\x41\x9c\x67\xb7\xdf\x45\x9c\x45\xed\x99\xb3\x27\xed\xc2\xc9\ +\xa3\xde\x99\xa3\x67\xdf\xf8\x77\x3f\xf8\xc1\xaf\x4f\x82\x27\xe6\ +\xe6\x1c\xa9\xa9\x85\x39\xf7\x46\x05\x68\x72\x9f\xdc\x5f\xb6\xab\ +\xf7\x1f\x59\x05\xb8\x75\x21\xc7\x01\x0b\xd1\x22\x98\xad\x95\xf3\ +\x29\x26\x0c\xfb\x23\x6a\x3c\x20\x59\xc7\xf6\x2a\xcb\x03\x48\xac\ +\xcf\xb1\x5a\xb4\x6c\xb0\x26\x2f\xf2\x53\x30\x22\x20\x43\xd7\x88\ +\x84\xe5\x1c\xbb\xc8\xe7\x06\xdf\x6d\x22\x82\x3a\xd0\x0d\x2d\x0e\ +\x57\xa9\x60\x44\x59\xb8\x6b\x77\x9c\x47\x9a\xe3\x83\x9b\x4b\x74\ +\x90\xaa\xb5\xf9\xee\xed\x65\x65\xba\x6f\x09\xca\xa6\x23\x05\x1a\ +\x66\x2e\xc5\x29\x3b\x75\x74\xde\x05\x79\x73\x67\xdf\x1e\x3d\xfa\ +\x62\x12\x98\x88\x80\x6f\xfe\xe6\x4b\x97\x06\x9d\xde\xe5\x31\x3d\ +\x5f\x28\x88\x52\xd3\xa4\xda\x36\x2b\x7b\xb4\xaa\xba\xab\xf1\xd9\ +\xe9\x02\x75\x08\x49\x01\x77\xa9\x2f\x72\x62\x9b\xcd\x06\x02\x26\ +\x48\xbd\x2a\x18\x7e\x57\x0e\x0a\x8e\x34\x88\x02\xe9\xc4\x91\xb2\ +\xcf\xfb\xb2\xc7\x0a\x90\xc8\xb2\x4b\xbb\x95\xb0\x51\x50\x05\xf5\ +\x36\x76\xb8\x8b\xc2\xf3\x28\xa3\xbb\xd4\xfb\x87\x37\xee\xb8\x96\ +\x2b\x19\xfd\xdf\xae\xbc\x63\xef\x7c\x72\xdb\x56\x37\x76\xec\xd3\ +\x07\x0f\xed\xc1\xda\xa6\x15\xd3\x09\x3e\x0b\xeb\x52\x70\xd4\x16\ +\x89\x7a\x64\x4b\x6b\x1b\xd8\xec\x47\xf6\xd1\xad\x7b\xde\x47\xf7\ +\x1e\x7d\x61\x1b\x9c\x18\x80\xe2\x6c\xfe\x52\x3c\x9e\xb8\xac\x89\ +\x97\x73\x19\x8b\x61\x4a\x06\x44\x3b\x2c\xa1\xc1\x2b\xe0\x0b\x59\ +\xa3\x87\xce\x8f\xe6\x2d\x92\xcc\xdb\xb8\x4b\x57\x80\x0f\x76\x6b\ +\x1d\x90\x93\xb1\x7c\x22\x69\x51\xcc\x51\xab\xb9\x6b\xad\x5e\x13\ +\x8b\x0c\x34\x09\x8c\x60\xad\x49\x3a\xf4\xa0\xf1\xa5\xe5\x13\x2c\ +\x4a\xfa\xa2\x83\x90\xa9\xb7\xba\xf6\xf1\xd2\x9a\xfd\xe4\xea\x2d\ +\xbb\x76\xf7\x81\xfd\xec\xe3\xdb\xf6\xc9\xbd\x65\x0c\x53\xd5\x0a\ +\xf8\x80\x59\x32\x7b\x7b\x79\xd5\xd6\x2b\xbb\x8e\x37\x98\x0a\x2a\ +\xd1\x73\xc9\x59\xa3\x15\x6f\xd3\x9d\x54\x3c\xd7\xa8\xff\xca\x41\ +\xdd\x7d\x26\x1d\x40\x8b\xf8\x72\x3a\x40\xed\x63\x26\x3b\x05\x73\ +\x97\x2c\x93\x4a\x03\x53\x1c\x16\x93\x17\xeb\xa7\x63\x31\x10\x10\ +\xb2\x0e\xd9\xf6\xbc\xa6\xf9\x81\x9d\xca\x83\x7c\xd2\xfb\xd1\xfd\ +\x64\x4d\x8e\xcd\xcf\xec\xc4\x17\x11\xf4\xbd\x24\xae\x32\x2b\xaf\ +\xaf\x52\x08\xf2\xbe\xcc\x93\xc8\x4e\xfa\x3d\x4a\xab\x2c\x63\xae\ +\xce\x1c\x5d\x70\x7c\xd0\x23\x18\x43\xda\xa1\x6c\xb4\x50\xe3\x47\ +\x37\x88\xd8\xc4\x35\xa7\xe7\xcb\x2c\x12\x1e\x60\x9e\x3d\x8c\x51\ +\x08\x45\x7a\x77\x65\xdb\xee\x3c\xdc\xb4\x0a\xf6\xfc\x1e\xaa\x51\ +\xd7\x12\x6f\x49\x14\xa8\x14\x1f\x37\x26\x06\xe0\xb9\x13\xa7\x10\ +\x17\x19\x3b\x7b\xf2\x24\xd9\x27\x7b\x94\x82\x7c\x40\x03\x68\xc2\ +\x32\xee\x02\x05\x02\x24\xed\x7d\x80\x74\xf5\x87\xe2\xe6\x91\xd5\ +\xba\x87\x57\x87\x8a\x9d\x65\x25\x2b\xd1\x78\x06\xd6\x4e\xb9\x1d\ +\x22\x6d\x8a\x68\x2f\xc1\x07\x12\x02\x4c\x3a\x02\x41\x4a\xbc\xb4\ +\x3b\x1d\xb7\x51\xa2\x76\x18\x80\xe0\xb4\xb3\x23\xce\x91\xa2\x94\ +\xb4\xd5\x42\x12\xf1\x28\x08\xe9\x39\xc9\x7b\x6c\xae\xe4\x08\x4e\ +\x7b\x01\xe2\x17\x17\x6c\x02\x2a\x92\xfe\xf9\x5e\x02\xba\x1f\x69\ +\x2e\x29\x3e\x46\x87\x4c\xf4\x40\xff\x77\x4c\x0c\x40\x2e\x9b\xb2\ +\xa9\x64\x84\x36\xd7\x87\xb8\x70\x78\x5c\x58\x17\x68\x7a\x43\xa7\ +\xd9\xfd\x11\xec\x2c\x4c\x2b\x2e\x18\x0d\xc9\x2e\x25\x91\x4b\x4d\ +\xd9\x91\x99\x59\x68\x50\xa4\x87\x8d\x25\x20\xc1\x40\x04\x54\xd0\ +\x01\x48\x57\xb7\x87\x14\x67\x65\x62\x6f\xf1\x46\x98\x12\x51\x7b\ +\x8c\x20\x97\xb5\x77\x30\x82\x13\xae\x23\x97\x1f\x52\xdb\x09\x82\ +\xf3\xc4\xe2\xbc\x9d\x3a\x26\x44\x24\x9c\x59\xda\x84\xf4\x04\xeb\ +\xfd\x5a\xd3\x71\x8b\x5a\x9e\xec\xaf\x10\x24\x2d\xa2\x45\xf7\xf9\ +\x5b\x64\x29\xe2\x49\x81\xd4\x8b\x67\x8e\xdb\x6b\xcf\x3f\x69\xaf\ +\xbc\xf2\x8a\x5b\xd7\xa4\x31\x31\x00\xd5\x83\x86\xb5\xda\x3d\x6b\ +\xbb\x3a\xa3\xaf\x27\xd2\x36\x62\x21\x71\x26\x9d\x4c\x26\xad\x58\ +\x9c\xb6\xe9\xa9\x29\x8b\x53\xeb\x7e\x16\xd7\xa6\xba\xa6\x72\xd3\ +\xb6\x58\x9a\xb5\x2e\x93\x90\x73\x53\x09\x68\x52\x9a\xa8\x32\x2a\ +\x7f\xa0\x6e\xa0\x40\xba\x6d\x2f\x55\x3e\xc2\x47\x22\x2a\x40\x06\ +\xeb\xd2\xf2\xf8\x02\x71\xc7\xdf\xf8\xc6\x45\xfb\x1d\x5e\xbf\xf1\ +\xb5\xd3\xd4\x7a\x0b\x47\xd9\x46\x68\x6d\xda\x0f\xde\x7a\xdf\xfe\ +\xcb\x8f\xdf\x63\x6e\x9e\x5b\xb8\xce\x2d\xd3\xe4\xb6\xde\x84\x2e\ +\x4d\x9e\xeb\x5f\x3c\x7b\xc2\xfe\xfa\xf3\x4f\xd9\x6f\x3c\x79\xda\ +\xce\x51\x56\xaf\x1c\xfd\x62\x2d\x3c\x31\x00\x5b\x1d\x32\x3f\x82\ +\x98\x90\x98\x22\xb0\x30\x6d\xa8\x4d\xcd\x8f\x40\x43\x07\xed\x0e\ +\x88\x2d\x4a\x76\xa3\x58\xd6\xae\x22\xdf\x15\xa3\x8f\xc9\x26\xad\ +\x8a\x33\x36\x39\x4e\x1b\x23\x62\x6e\xd5\xa1\x3a\x80\xda\x59\x1f\ +\x2e\x10\x44\xab\xf8\x02\x45\xc5\x6d\x8e\x32\x71\x65\x4d\xc8\x78\ +\x86\x89\xbf\xf2\xc2\x93\x08\xa6\x34\xa2\x2a\x86\x71\xd2\x7e\x01\ +\xf5\xee\x20\xdd\xb3\x3d\x12\x53\xa9\xd6\x9d\xfc\xe5\xc4\xee\x98\ +\x0b\xc7\xe7\xec\xe5\xa7\xcf\x3a\x4f\xa2\x21\x05\xf8\xd2\xf9\xd3\ +\x6e\x7f\x20\x19\x8b\xbb\xd2\x7b\xdc\x98\x18\x80\x44\x0c\x73\x91\ +\xc8\xd2\x57\x03\xb6\x51\x39\xb0\xa5\xa5\x87\x4e\xd9\x29\x53\x61\ +\x26\xde\xa3\x57\x6b\x1f\x60\x17\x35\x16\x0c\xb2\x90\x70\x9c\xbe\ +\x1e\x3a\x74\x80\x64\x38\x0c\xac\xb5\x9b\x33\xa2\xb5\x49\xa5\xf5\ +\x5c\x9b\x83\x1c\x29\x25\x91\x5a\x10\x22\x94\x70\x51\xc6\x24\x5c\ +\x82\x04\x52\x46\x4a\xa2\xc6\x47\x20\x43\x04\x4b\x25\xb4\x07\xe4\ +\x13\x74\x20\x79\x09\x91\x5d\x31\x2b\x4b\x0e\x61\x22\x75\x67\x8b\ +\x39\x3b\xb3\x38\x63\xbf\x77\xe9\x59\x7b\xee\xe4\x82\xcd\x4d\xe7\ +\x1c\x22\x84\x34\xb5\x4f\x21\x49\x9c\xa3\xeb\x3d\x6e\x4c\x0c\xc0\ +\xb0\xd7\xb2\x41\xad\xc2\x04\xc7\x98\xa2\x9e\x6d\x13\xf9\x31\x0b\ +\xd3\x22\x73\xf4\xdc\xa9\x4c\xd6\xed\xc0\x8a\x74\xe4\xff\x25\x47\ +\x6b\xe8\xfe\x0e\x7f\x6f\xd5\x0f\x50\x82\x43\xc7\x0f\x9a\x90\x08\ +\x8f\x96\x6e\xeb\xbb\x08\x92\x9d\x8a\xd5\xf0\x13\xda\x52\xd0\x3e\ +\x5f\x97\x89\x4a\xcb\x93\x60\x5e\x94\x04\x88\x08\x41\x84\x7d\xd8\ +\xff\xd6\xc3\x47\xf6\x1f\xff\xe4\xc7\xb8\xc8\x26\x7a\x43\x04\x09\ +\xc9\x51\x0a\x1e\x2a\xb4\x43\xa0\xc5\xee\x9b\x58\x71\x11\xb3\x9c\ +\xe7\x8b\xe7\x9f\x70\xf2\x5c\x81\x11\x01\x6b\xdf\x41\x08\x13\xf2\ +\x1e\x37\x26\x06\xe0\xfe\xea\xb2\x35\xa8\x2d\x49\xde\x6a\x6d\xcf\ +\x3c\x32\x37\x7b\x74\xd1\x8e\x9e\x3c\xc1\x64\x82\xbc\x0f\x31\x2a\ +\x53\x84\x48\xf0\x34\x5f\x8f\xd6\x66\x0e\x6e\x49\x24\xb0\xb2\x24\ +\xa1\xa3\x95\x49\xec\xd4\xdb\x1d\x26\xe5\x43\x97\x17\x71\x7a\x69\ +\x08\x74\x48\x19\x74\xb0\xb7\x7b\xd6\x07\x1d\x62\xf3\x21\xd7\xea\ +\x43\x76\x0d\xf5\x6f\x16\x9d\x4b\x67\xec\xe2\x85\x93\xb6\x38\x5b\ +\xa4\x44\x0e\x33\x29\xd2\x93\x76\x10\xc3\xcb\xf5\x69\x3f\xf1\xde\ +\xfa\xb6\xad\xed\xd7\x6d\x63\xf7\xc0\x4e\x2d\xcc\xd8\xdf\x7c\xed\ +\x65\x9b\xa3\x74\xa4\x38\x74\xfc\x50\x11\x7e\xcc\x98\x18\x80\x08\ +\x0c\x9a\x41\x59\xa5\x52\x88\x9a\x6c\x11\x47\x37\x87\xd0\x81\xb9\ +\x13\x39\x52\x4a\xdd\x03\x6d\xf5\xf0\x6e\xbf\x63\x7b\x7b\xbb\xc0\ +\xf6\x50\xe9\x89\x03\x72\x68\x7b\x6d\x8a\x06\xd5\xce\x28\x19\x71\ +\x83\x3c\xc1\xb1\xf9\x39\x9b\xc6\xbf\x47\x68\x89\x55\x08\x4f\x9e\ +\x61\x75\x6b\xcf\xb1\xfe\x80\xf3\x29\xab\x6b\x38\x4d\x0f\x31\xb4\ +\xb7\x5d\xe5\x67\xdb\xce\x2e\xcc\xdb\x73\x67\x8f\xdb\x33\x4f\x2c\ +\x20\xb0\x10\x4c\x8e\xe5\x98\x34\xe7\x15\xc1\xaa\x34\xae\xdd\x5b\ +\xb1\xff\xf1\xb3\x6b\xf6\x67\xd7\x6f\x59\x83\x80\x28\xf3\xda\x8c\ +\x3d\xa4\xc8\x5f\x3d\xbe\x80\x03\x32\xd6\x69\xa3\xe0\xf0\xfc\x3e\ +\x6a\x4a\x66\xc4\xed\xec\xec\xd5\x81\x27\x19\x20\xb2\x41\x4c\x4a\ +\x18\x93\x13\xa1\xce\xc4\x7c\x22\x29\xd5\x9f\x2c\xd2\x3e\x13\xd1\ +\x56\x38\x20\x02\xa2\x5d\x7e\xc7\xa3\xb3\x60\x67\xa8\x58\xc4\xda\ +\xde\xbe\xbd\x85\x9c\xbd\xb9\xb2\x6e\x6f\x5d\xbf\x6d\xff\xfb\x83\ +\x1b\xb6\x8a\x9b\x7c\xb8\xb3\x43\xb7\x21\x90\x10\x6f\x0f\x84\xb4\ +\x41\xc2\x14\xc9\x38\x33\x5b\xb2\x67\xa9\x73\x95\x9f\x10\xa0\xc5\ +\x6b\xaf\x41\x9b\x2a\x52\x84\x9a\x9f\x38\x62\x07\xf4\xe8\x3e\x43\ +\x50\x9d\x85\x20\x28\x01\x93\x57\xf8\xff\xc6\xc4\x8f\x77\x5b\xfb\ +\xd6\x01\xf6\x20\xcf\xe2\x31\xf9\x7d\x69\xe6\x91\x25\x0c\x0f\x4f\ +\x50\xae\xdd\xbb\x63\x77\x57\x1f\x59\xd6\xf9\x7e\x9f\xc5\x33\x79\ +\x5a\x62\xd4\x0e\xba\x04\x0d\x35\x38\xa2\x38\xea\x68\x86\x83\x7a\ +\x9d\x32\x18\x40\x6a\xaa\x06\x72\xc2\xab\xd1\x6c\xba\xcc\x37\x09\ +\x92\xca\x44\x5b\xe6\xf2\x18\x3f\xbd\x7a\xd3\xdd\x55\x2a\x96\xf2\ +\x96\xd2\x0e\x31\x0b\x72\xa5\x21\x74\xf1\x7b\x39\x97\x75\x41\x48\ +\x27\x29\x2f\xe6\x78\xc8\x6d\x42\x57\xd8\x4e\xcd\x15\xad\x0c\x42\ +\x5a\x04\x62\x0f\x1e\x92\xbe\x90\xb0\x72\xad\xf8\xf1\x1c\x38\x39\ +\x00\x82\xe4\x68\x24\x6b\x1a\x26\x10\x1c\x12\x8c\x5a\x03\x13\x94\ +\x2c\x94\x6c\x7e\x66\x1e\x83\x94\x43\x22\x27\xad\x52\xab\x5a\x28\ +\x4a\xa4\xfb\x07\xee\x7b\x31\x8e\x47\xc5\x22\x56\x68\x73\x4c\x5c\ +\x1e\x22\x10\x8a\xb2\xb0\x18\x3c\xa1\xc9\x8c\x58\xec\x3e\xe5\x62\ +\x96\x42\x0c\x4d\xc7\x13\x36\x4d\xc9\x64\x59\x44\x93\x12\x68\x23\ +\x28\x12\x98\xaf\x99\x23\x65\x9b\x3b\x52\xb2\x45\x5e\x0b\xe5\x69\ +\x54\x67\xda\x09\xa6\x32\x02\xed\xb7\x9f\x3d\x67\x4f\x1e\x9f\x81\ +\x90\xb9\x2e\xc1\x57\xc6\x15\x90\x59\x5a\xa7\xba\xd4\x3d\xcc\x13\ +\x71\x3e\x1c\x7c\x2e\x4d\xf2\xb8\x31\x91\x22\x17\x4f\xce\x5d\x4a\ +\x45\xb3\x97\xc3\x4c\x52\xfa\x7f\xc0\x09\x6b\xb5\x9a\x6b\x69\x4d\ +\xd8\x3b\x16\x22\xeb\x31\xc9\xda\x01\xb5\x99\x75\x9e\xbe\xdd\x63\ +\x71\x30\xfc\x83\xed\x4d\xf8\x23\x6a\x73\x53\x59\x57\xab\x2a\xdb\ +\x36\xc2\x45\x37\x4a\xe5\xfc\x7e\x7a\xed\xa6\x6d\x23\x78\xf4\x99\ +\xa4\xb0\xf6\x07\xe4\x2a\x0b\xc0\xfb\xc8\xec\x0c\x82\x2a\xe5\x64\ +\xb7\xb3\xd9\x04\x51\x59\xd6\x5e\x40\x06\x93\xe5\xca\x4a\x84\x8c\ +\x4c\xcf\x17\x93\x76\x04\x73\x94\x82\x70\xb9\x34\xd7\x6e\x38\xd4\ +\xe8\x3a\x33\x85\x3c\x56\xb9\x6b\x4b\xab\xeb\xf6\xa7\xef\xbc\xef\ +\xfd\xcf\x8d\xf7\xbf\xdc\x8e\xd0\xd3\xcf\x9c\xbe\x84\xcf\xb8\x1c\ +\xa5\xc6\xa3\xd1\xa4\x75\xe8\xf7\x31\x7a\xf4\x10\xf6\x6d\x23\x7d\ +\x13\xf4\xd8\x78\x34\x84\x20\xa1\xd6\x21\x9d\x0d\x3c\xf7\xf6\xfe\ +\xbe\xad\xec\x6c\xb8\x00\x2d\x14\x0a\x4e\x8a\xba\xc5\x7b\xda\x19\ +\x1a\xda\x16\x4c\x3d\xe2\x3f\xdd\xd4\xf4\x68\xad\x32\x54\xd3\xb9\ +\x34\x92\x3b\x66\x47\xf2\x19\x3b\x09\xf4\x57\xb6\xb6\xed\xfe\x66\ +\xc5\xf5\x6f\xdd\x18\xd5\xf2\xf7\x10\x3d\x2b\x68\x91\x36\x84\x52\ +\x2e\xa1\x40\xa7\x8b\x4e\x23\x44\x40\x53\x81\xc0\x9f\x41\x2e\x9f\ +\x82\x2c\x75\x2b\x6d\x6d\x67\x8f\x8e\xe3\x61\x8e\xd6\xec\xea\xed\ +\x7b\xc8\x67\xd0\xe6\xf3\x79\xa5\x70\xff\x8d\xeb\x5f\x26\x00\x8b\ +\xc7\x8f\x5e\x0a\x87\x22\x97\xd3\x98\x90\xb8\x36\x45\x99\x90\x87\ +\xb2\x73\xdb\xdc\x83\xb6\x4d\xa5\x0b\x6e\x33\xa2\x42\xed\x76\xe8\ +\xc7\x2d\x11\x26\x67\xc2\x15\x20\x67\x0f\x2c\x4e\xe0\x84\x8a\x3e\ +\x02\x40\x7b\xfe\x4d\x14\xe5\x8d\x07\xcb\x26\x1f\xa1\x16\x17\x81\ +\xa0\x4a\x53\x69\x7b\x12\x76\x3f\xc2\xcf\x0c\xd7\x51\x07\x11\xab\ +\xdf\xc6\xc7\x37\x51\x8a\xdb\x7b\xea\xf1\x5d\xbb\xbb\xbc\x46\x5b\ +\xde\xb0\x55\x34\x84\xee\x18\xab\xb7\xe7\xb2\x19\xa7\x1e\x65\xa2\ +\xa4\x37\x24\x96\x3c\x32\xde\xc4\x9d\x6a\xfb\xde\x91\x36\xd0\xd7\ +\x1d\x67\xc4\x93\xe7\xf7\x97\x08\xc0\xe4\x2d\xb1\x89\x1c\x50\x76\ +\xdb\x60\x87\x85\x34\x86\xc4\x74\xb1\x04\x8b\xef\xd0\xff\x77\x59\ +\xa0\xf6\xf9\xe3\xc0\x2d\x09\xfc\xce\x9d\x39\x67\x53\x4c\x48\xd0\ +\xb5\xc0\x08\xa6\x4e\x21\x51\x93\x4c\x2e\x44\x3b\x1c\xb2\xf8\x0e\ +\x4c\x7f\xc3\x6a\xad\x06\xf6\xb5\x6b\x59\xea\xb9\x98\x8e\xbb\x7a\ +\x8d\x86\xb5\xdb\x13\x83\xe4\x10\x3a\x2c\xa6\x90\x4e\x5a\x46\xdb\ +\xea\x64\x13\x06\xb4\xd5\xf5\x0d\xc3\x6e\xd9\x85\xd9\x82\x85\x7c\ +\x23\x7b\xb8\xb2\x6a\x3f\x7a\xef\x7d\xfb\xef\x57\xfe\xdc\x6e\xd1\ +\xff\x03\xa1\x08\xe5\xc3\x11\x5c\x67\xbb\x5a\x45\x63\x44\xed\x68\ +\x29\x63\xb3\xb9\x04\xb6\x3d\x62\x8b\xe5\x1c\x65\xf6\x59\xef\xfc\ +\x82\x31\x31\x00\xcf\x5d\x38\x63\x39\x26\xa6\x76\x92\xa5\xf6\x3a\ +\x90\x62\x8d\x4c\x4f\x15\x66\xac\x06\xa4\x2b\xf5\x1d\xd7\xb7\xf7\ +\x71\x71\xab\x5b\xab\x16\xa2\x5d\x5c\xbb\xf3\xc0\x02\x03\xa0\x0b\ +\xf4\xb7\x1a\x55\xc4\x49\x85\x5a\x6e\xf0\x39\x99\x43\x08\x15\x52\ +\x09\x24\x74\x0b\x61\x33\xef\x4a\x43\xdb\xee\x12\x32\x60\x94\x60\ +\xf9\x11\x4a\x63\xb2\x19\xb6\xd3\x73\x33\xf6\xfc\x85\x53\x76\x02\ +\x22\xd4\xb3\x04\x12\x32\xc7\x91\xb9\xe7\xcb\x05\x44\x16\x9c\x24\ +\xe4\x91\x80\xf7\x3e\xb9\x65\x37\x1e\xae\x1b\x17\xb7\x26\x24\x30\ +\x24\x40\x12\x60\xf9\x44\xc6\x4a\x74\x8c\xe3\xb3\xd3\xce\x53\x04\ +\xf9\xce\xe3\xc6\xc4\x00\xec\xa2\xaa\xca\x2c\x56\x8f\xc1\x74\x7a\ +\x1d\x77\x0b\xac\x98\xcb\xd9\xd2\x0a\xad\x0f\xa8\x96\x11\x47\x83\ +\x71\xc0\xf2\xa9\x3c\xda\x60\xd7\x3e\xba\xb3\x84\x78\xd2\x1d\xe4\ +\x00\xa5\x72\x28\x6a\x2e\x2c\x2e\xda\xc3\xb5\x5d\x5b\x5a\xdf\x72\ +\x0f\x34\xcc\x4d\xe5\x6c\x06\x07\x59\x4a\x47\x80\x70\x96\x3a\x1e\ +\xe1\x33\xf6\x5d\x2f\x1f\xd2\xab\xda\xc0\x5d\x6d\x5b\xfa\xfe\xe4\ +\xdc\xb4\xbb\xc9\x21\x02\xaf\xb5\x3c\xea\x7f\x68\x27\x4a\x53\x76\ +\xaa\x4c\x8b\x94\x8d\xf6\x61\x70\x58\xf0\xc7\x4b\x4b\xf6\xc7\x3f\ +\x79\xd7\xed\x12\x95\x40\x96\x07\x12\x96\x0f\xf6\x48\x5c\x00\xd2\ +\x8c\xd9\x3e\xe8\xdb\x6e\xd4\xec\xd1\x63\x6e\x0c\x4c\xe4\x80\x27\ +\xce\x1e\xbd\x04\xb9\x5d\xae\xd6\xd0\xdb\xd4\xb9\x02\x20\xf8\x16\ +\x58\x44\xa1\x38\x8b\x3e\xaf\x59\x52\x04\x89\xdb\x1a\x74\x1b\x76\ +\x72\xb6\x6c\x33\xb9\x3c\x8b\x41\x3e\xd3\x96\xa6\x80\xf2\x7c\xb1\ +\x64\x6f\x5f\xbd\xe1\x9c\x5f\x29\x87\xac\xc5\x9b\xcf\x17\x72\xae\ +\x6f\xcf\x4c\x97\xe0\x90\xc3\x9d\x23\xf9\x8d\xa5\xf5\x1d\x77\xdb\ +\xbd\x10\x47\x57\x50\xe3\x7e\x7a\xb8\xcc\xd4\x32\xe8\x51\x17\x58\ +\x98\x86\xed\xf9\x5e\x9a\x5a\x0f\x13\x4c\x05\xd9\xf3\x28\x4d\xb2\ +\x5b\x85\x53\xd6\x36\xf7\x31\x53\x61\x44\xd6\xd0\xd2\x9c\x43\x4a\ +\x70\x8b\xae\xe0\xee\x5c\x85\xc2\xde\x94\xcd\x7c\x39\x0e\x48\xd0\ +\x76\x76\x1b\xfb\x44\xd2\x6f\x7b\xb5\x03\x04\x4d\x83\xec\xc8\x04\ +\xfb\x9d\x22\x4c\xd1\x19\x76\x61\xf5\x9d\x7d\x7c\x02\x93\x39\x52\ +\x42\x88\xd0\x9a\xca\xf0\x40\x11\xf2\x3b\x0d\xcc\x0f\x50\x65\xba\ +\xc1\x81\x1d\xb1\xe9\x29\xdd\xd1\x09\x99\x87\x0c\xec\xd2\x53\x37\ +\x77\x2b\x4e\x1d\xfa\xfd\x21\x6a\xb7\x85\xae\xa7\xcd\x7d\xe6\x1f\ +\xf4\xe8\x8c\x5e\xf2\x10\xda\x15\x52\x93\x57\xb0\xf6\x20\xd0\x47\ +\x74\x9b\x2a\x76\x3c\x42\x7b\xce\x53\x6a\x59\xbe\x97\x42\x7b\x8c\ +\x90\xde\xf7\xd6\x29\xb9\x06\x9a\x80\x6b\x74\xdc\x6e\xd0\x08\xb4\ +\xa5\x40\x5d\xca\x1e\xb3\x1d\x30\x39\x00\x19\xe0\x37\x44\xd1\xe4\ +\x20\xb3\x2c\xa6\x64\x75\x6b\x03\x58\xf7\x69\x75\x7b\x4e\xd5\xe5\ +\xa9\xb1\xb8\xa4\x2d\x90\xeb\xa0\xf8\x76\xf1\xe8\x31\xf4\xfe\x0c\ +\x99\xce\xd3\xcf\x7b\x74\x8c\xb5\x6d\xb2\x4a\xb0\x12\x89\x08\x24\ +\x99\xb5\x1b\x95\x6d\xfb\xf3\xe5\x87\x76\x7b\x77\xdb\x3e\xc1\x5e\ +\xaf\x6e\xae\x5b\x85\xf2\xa9\xe2\x22\xdb\xa0\x26\x92\xce\x59\xad\ +\x0f\x1e\x9c\x5c\x3e\xdc\x2b\x10\x07\x64\x53\x71\x82\x54\xb7\xbb\ +\xa0\x64\xeb\x40\xb7\xe1\xb5\xf7\xe8\xb7\x24\x88\x90\x0b\x4c\xa0\ +\xfa\xf4\xf2\xe8\x34\x3b\xbb\x70\xce\x06\x6e\x94\x1e\x9e\xe2\xbd\ +\x2c\x73\xd2\x31\x8f\x1b\x13\x03\x10\x0c\x24\xec\x89\xb9\x45\x8c\ +\x4d\x9a\x3e\x7b\xc2\x6a\xc0\xff\xc6\xfa\x5d\xe7\xca\xf4\x15\x7d\ +\x29\xca\x24\x16\xcb\x25\x3b\x3e\x77\xc4\xed\xcb\xd7\x74\xaf\x80\ +\x85\xec\x40\x7c\xb7\x70\x93\xbb\x12\x4e\x30\xb8\x08\xef\x00\x14\ +\xd5\x1a\x0d\xdb\x41\x39\xd6\x9b\xc8\x63\x3a\xbc\xcc\x13\xb0\x80\ +\xa4\xe8\x02\x91\xa4\xdd\x7d\xb4\x6a\xf7\xb6\x2b\xf6\xa8\xda\x01\ +\xba\x03\x7a\xfa\xbe\x73\x80\xe2\x05\xdd\xfa\x76\x37\x53\x11\x3c\ +\x3a\x9f\x36\x48\x73\xa0\x4b\xa8\xc9\xd3\x51\xa6\x09\xfa\x3c\x64\ +\xdd\xeb\x0e\x21\x48\xe6\x01\x4a\xf2\x88\xb1\x74\x32\x6a\x0b\xf9\ +\x29\x3b\xfa\x98\xbb\xa3\x13\x03\xb0\xc6\x02\xee\x3d\x78\x68\x77\ +\x1e\xde\xb3\xfd\xea\xae\x7b\x0a\x63\x6b\xab\x6a\xd7\x1e\xdc\x71\ +\x75\xe6\xf7\x63\x86\xa8\x3f\x0f\x38\x6b\xe7\x67\x71\x0e\x66\x07\ +\xe2\x0d\xb2\x30\x85\x63\x8c\xf8\xb5\xdf\x27\x43\x12\xa2\xce\x87\ +\x7c\xbf\xef\x1e\x5c\x98\x8a\xc4\xad\x0c\x4b\x7b\xc0\x53\x37\x55\ +\xb4\x55\x1e\x05\x49\x12\x7d\xc3\x51\xdf\x29\xc6\x9d\x1d\xc4\x10\ +\x72\x76\xe8\x0b\x51\x5a\x25\xb7\xeb\xa4\x5b\x6f\xca\x7a\x9c\xac\ +\x0a\x15\xe2\x91\x01\xb0\x97\x5a\x9c\x81\x97\x9e\x3a\x76\xc4\xed\ +\x05\xe4\x28\x0b\xed\x14\xef\x35\x3c\x6b\x70\xbd\x19\x82\x12\xa3\ +\x93\x3d\xee\xee\xf0\x44\x7c\xbc\xf6\x8d\x97\x2e\xf1\xc5\xcb\x09\ +\x44\x85\xbb\x29\x4c\x1a\xc4\x03\x7a\xe4\xe4\x34\xfa\x5c\x77\x81\ +\xb5\x85\xd5\xa4\xd6\x44\x38\x45\xfa\x2f\xdd\x0c\x66\xef\x39\x19\ +\x5a\xc0\x1c\x69\xf3\xc4\xc7\x22\xf4\x60\xa4\x26\x7e\xb2\x5c\xb6\ +\x34\xa2\xaa\x0d\x31\x69\x93\x43\xb6\x35\xae\x07\x19\x52\x59\x6d\ +\x23\xa3\x32\x3b\x76\x20\x83\x84\xe2\xd3\xad\x2d\x8f\x16\x9b\x4b\ +\xa5\x68\xbd\x45\x82\x8c\x86\x84\x17\x52\xa8\x46\x11\x6c\x96\xda\ +\xce\x66\xf3\x96\x83\x5b\x64\x8e\x74\xcf\xf0\x00\xd2\xf3\x13\xd4\ +\x31\x8a\xac\x8a\x94\xce\xc4\xe3\x4e\x83\xec\xd5\xda\x5e\xc3\x3b\ +\x78\xe3\xca\x95\x2f\x41\x82\xba\x03\x3c\x84\x6d\xd5\xaa\xc2\x2c\ +\xa2\x4b\x1f\x3f\x52\x2c\x3a\xf9\xfa\x60\x7d\xd3\x3d\xcf\x93\x8c\ +\xfa\xcd\x37\x44\xb3\xcb\x00\xc1\xd8\x82\x66\x3a\x91\xa2\x15\xea\ +\x49\x32\x1f\x50\xef\xb2\x40\xc1\x35\x64\xfb\x74\x82\xbb\xcb\xeb\ +\x76\x7f\x79\xc3\x1e\x6e\xee\xb9\x3a\xe7\x7f\x6e\x67\xa8\x4b\x80\ +\xb4\x63\x9c\xc2\x18\xb5\xf5\x00\x14\xc1\xd5\x82\x3d\x82\xbb\x81\ +\xfa\x5b\xde\x58\xb3\x1d\xbe\x9f\x84\x77\xb4\x19\x3b\x43\xc9\x65\ +\x59\xb8\xe0\x6f\x7d\xba\x14\x5c\x73\xfb\xe1\x2a\xe4\xaa\x27\x4c\ +\x47\x10\x24\x3c\x02\x32\xc7\x2c\x2d\x9b\x4a\xbb\x67\x8a\x1e\x37\ +\x26\x22\xe0\xb9\xf3\xa7\x2e\xed\xb7\xda\x97\x45\x46\xee\xc4\x5d\ +\xcf\x4d\x56\x7b\x7d\x5b\xe8\x6b\x3d\xc8\x30\xad\x96\x06\x27\xf8\ +\xd4\xc3\x91\xc2\x92\xa3\xba\x5f\x40\xa9\xda\xf5\x3b\xf7\x09\x84\ +\xcf\x22\xd1\xa0\x95\xa6\x33\xee\x7e\x3f\x78\xb5\x31\x48\x92\xb1\ +\x72\x37\x44\xb4\x78\x0e\x16\x37\x54\x51\x89\x6b\x9c\xb7\x02\x21\ +\xaa\x35\xea\x2e\x93\x7a\x79\x9f\xac\x17\x21\x51\x3d\x5f\x08\x16\ +\x1d\xbb\xeb\x5e\xa2\x0c\x91\xf6\x0b\x37\xd1\xfe\xda\x2a\x97\x0f\ +\xe8\x13\x3c\xb9\x43\xcd\x41\x5b\x72\xda\x7c\xc9\xc2\x01\x94\x89\ +\x37\x4b\x1b\xfc\xc1\x95\x2b\xbf\xbe\x17\x38\x79\xfa\xe8\x25\xd4\ +\xdf\xe5\x06\x42\x48\x34\xa6\xfd\x15\xf9\x76\x6d\x80\xea\x06\xc5\ +\x2e\xae\x6f\xaf\x56\xb7\x59\x50\x91\x47\x80\x68\xd4\xf0\xe1\xd2\ +\xdf\xf7\x57\x36\x6d\x1d\xed\x20\x05\xa9\xdb\x55\x32\x24\xf2\xfe\ +\x6a\x89\x5d\x26\x2e\x22\x95\x5e\x97\x03\xd4\x53\xa7\xba\xc6\x2e\ +\xe5\xe5\x75\x06\x4e\x48\x95\x31\x46\xba\x47\x20\xe7\x38\x0b\xd2\ +\xca\x74\x01\xed\x07\x4c\x73\xac\xb2\x5b\xe5\xd8\x1b\x8f\x36\xdd\ +\x3e\x65\x02\xd4\xb8\xad\x79\x39\x4a\x38\x27\x84\x48\x2a\x60\xc4\ +\x92\x74\xae\x1c\x88\x39\xbc\x49\x62\x5e\xc2\xa2\x5f\x18\x00\x21\ +\xf7\x17\x06\xcc\x1b\xf9\xe6\x6b\x2f\xff\xbd\x78\x2c\xfc\x3d\xed\ +\xce\xaa\x8e\xf5\x7c\x80\xab\x65\x4c\x8b\x76\x60\x64\x70\xf4\x64\ +\x47\x0e\x88\x3d\xff\xe4\x19\x47\x50\x7a\x4c\xa6\x09\x12\xb6\x76\ +\x6b\xb6\x5f\x6f\xf2\x39\xd6\x94\xf0\x29\x23\x29\xda\xd1\x7c\x21\ +\x0b\x63\xa7\x9c\xdc\xed\x13\x4c\x3d\xf2\xa2\x36\xb9\x42\xb0\xf6\ +\xb5\xd5\xee\x87\xd9\xc9\xf6\xab\x2f\x3e\xe9\xcc\x4c\x03\xa7\x99\ +\x80\x6c\x47\x94\x83\x5a\xe2\xe1\x4d\x54\x5c\x64\x32\x85\xfa\x0d\ +\xdb\xdd\xb5\x2d\xdb\xc0\x30\xcd\x63\xbb\xe5\x0e\xf5\xc8\x8e\xb6\ +\xdf\x14\x8c\x75\x50\x71\x6c\xae\x6c\x21\xff\x18\x7d\x92\xae\xc2\ +\x16\xb3\x7f\xeb\xf5\xd7\xc7\x04\xe4\x73\x0f\x4a\x7d\x2e\x00\xe3\ +\xf1\x38\xfe\xea\xef\xbc\xf2\x77\xa2\xc1\xd0\xf7\xc4\xb2\xd2\x22\ +\x09\x08\xa5\xe5\xa1\xf8\xe6\x8f\x92\xa9\x2a\xfa\x3c\x68\xc7\xca\ +\x73\x28\xc3\xb8\xdd\xa2\xb6\xb5\x2d\xf6\xe9\xca\x0a\x8b\x45\x9d\ +\xc1\x09\x5a\xa8\xa0\xad\x47\xeb\x4e\xcd\xce\x42\x92\x68\x72\xb1\ +\xa4\x9c\x21\x08\xba\x57\x6d\xd8\x98\xd6\xa6\x2d\xb4\x78\x98\x5a\ +\x45\x69\xd6\x09\xca\x6e\xab\x67\x27\x66\xf2\x76\x7a\xa1\xec\xee\ +\xf8\xea\x39\xc5\x3e\x01\xd0\xe6\xa9\x9e\x5a\xd3\x53\x68\x05\x48\ +\xd6\xed\x16\xf1\x5d\x21\xe7\xda\xd2\xb2\x65\x49\x4c\x9f\xcf\x5a\ +\x90\x67\x29\x93\xb5\x0d\xd0\x19\x96\x2e\xc1\x0b\xcc\x14\xd2\xd5\ +\x5c\x70\x66\xee\xf7\xbf\xf3\x1d\x21\x42\x4f\x91\xff\xc2\xf8\x5c\ +\x00\x34\x7e\xf3\xb5\x6f\xfc\x6e\x22\x12\xfe\x4f\xc8\xe1\xa4\x76\ +\x56\x23\x91\x18\x52\xb5\x69\xcf\x9e\x7d\xc2\x16\xa7\xb3\x76\x67\ +\x79\xcb\x8e\x62\x5a\x9c\xe4\xdc\xab\x42\x3a\x3d\xf4\x7a\xd7\x76\ +\xea\x75\x9b\x49\x65\xe0\x86\x18\x13\x88\x61\x6b\x6b\x9c\xcd\x0f\ +\x22\xf4\x64\xe7\xc8\xfa\x10\x5f\x30\x86\x32\x2b\x4e\x39\x19\x2b\ +\x02\xd5\xf3\x47\x01\x24\xf5\xfa\xfa\x1a\xe7\xda\xb3\xed\x7a\xdb\ +\xc9\xee\x08\x7c\x71\x12\x43\x73\xfe\xd4\x31\xda\x4b\xd7\xaa\x94\ +\x5d\x0b\xee\x51\x67\xc8\x6a\x6f\x50\x67\xe6\x18\xa1\xed\xbd\x4f\ +\xef\x39\xd1\x13\x8f\xe0\x50\x39\xd7\x8a\x9e\x16\x83\x68\x67\x41\ +\xdd\xb1\xd2\xd4\xfa\x7c\xe9\xec\xe9\xdf\xfe\xd6\xb7\x5a\x6e\x71\ +\xbf\x34\x26\x72\xc0\xb7\xfe\xe0\x6f\xdf\xbb\xff\xe0\xfe\x41\xd8\ +\x1f\x7c\xc6\xeb\x0f\x52\x29\xa2\x2a\x22\x12\x33\x47\x53\x53\xd8\ +\xdc\xb1\x5b\xd4\x9d\x95\x75\xdb\xaa\xee\x63\x8b\xe3\x36\x45\x3b\ +\xd3\xcd\xc8\x5c\x7e\xda\x82\xf1\xa4\xdd\x7b\xb8\x8c\x3f\x6f\x59\ +\x85\x96\xa7\xef\xe9\x69\x71\x89\x96\xb9\x6c\x82\x5a\x3e\x94\xc3\ +\x5a\xd4\x1e\x82\x49\x19\x8e\x22\xbf\xb3\x04\xef\x58\x79\x9a\xe3\ +\xa8\x77\x82\xe3\x91\xd1\x5b\x5c\xe3\xc1\xd6\xbe\xd5\xd1\x18\x72\ +\x9d\x43\x50\x26\x13\xa5\x87\xa9\x25\x94\x74\x9f\x50\xf0\x5f\xd9\ +\x02\x25\x08\x24\xb5\x6c\x75\x1d\xde\x1b\x97\x73\x99\xa5\x44\x3c\ +\xfa\xcf\xad\xf0\xee\xb5\x37\xdf\x9c\xfc\xac\xf0\xc4\x00\x5c\xb9\ +\x72\x65\x7c\xfe\x5c\xe1\xd3\xee\xc0\x5f\xed\x0d\x47\x4f\x06\xc7\ +\xa3\x0c\x76\xd5\xd7\x25\x8b\x7e\x7f\xd8\x59\x59\xed\xd0\xa4\x80\ +\xf6\x6c\x79\xd6\x7c\xea\xd3\x4c\xa6\xdd\xa6\xc7\xd7\x59\x14\x7c\ +\xd0\xf6\xda\x6e\x5f\x5e\xc8\x4f\x02\xf1\x1c\x8b\x8f\x45\xe3\xb8\ +\xca\xc3\xcd\x0c\x37\x59\x3e\xd3\xad\x2f\x4d\xba\x09\x89\xae\x6f\ +\x22\xb9\x3b\x0d\x67\x9b\xd5\xdf\xf5\xb4\x67\x87\xc0\x6b\xc3\xb5\ +\xc1\xf9\x2a\xf5\x96\x3d\x44\x21\x4a\x87\x1c\x50\x62\x6d\x6a\x5f\ +\xe5\x97\xa2\x04\x96\xd6\xb6\x6d\x65\x07\xa5\x09\x7f\xe0\x4f\x46\ +\x38\xd2\x0f\xbc\x4e\xe7\x9f\x6d\xb7\x02\x7f\xf4\xdd\xef\xfe\x87\ +\x89\x04\xa8\x31\xb1\x04\x7e\x3e\x5e\x7d\xf5\xd5\x04\xcd\xea\x72\ +\x2e\x93\xfc\x97\xe8\xae\x53\xf9\x7c\xda\x57\xce\x97\x40\xa4\x47\ +\xef\xee\xe3\x0b\xd0\xeb\x4c\x7e\x6f\xbf\xea\xb6\xc8\x76\xa9\xbd\ +\x6d\x5a\x99\xfc\xfd\x54\x86\x6c\xa3\xef\xb5\x4b\x1c\x24\x9b\x47\ +\xc8\x6c\x11\x51\xa3\x9d\x62\x26\xe6\xb6\xb8\x7b\x9d\xb6\x6b\x5d\ +\x75\x6a\x5f\x3b\xc0\x22\x57\xb7\xb1\xc2\x4f\x3d\x67\xb4\x81\xef\ +\xd7\xb3\x85\x32\x40\x1e\xd7\x54\x39\x8d\x28\x99\x3e\x79\xf3\x08\ +\x48\xd0\x7a\x56\x00\x7d\x27\x67\xa6\x9d\xeb\xec\x60\xa9\x9b\xbd\ +\xee\x08\xf4\xbc\xb3\xba\x57\xf9\xa7\x0f\xc3\x5b\xef\xdd\x7c\xf3\ +\xe6\x63\xff\xd1\xc4\x44\x04\xfc\x7c\xe8\x1f\x1b\xfc\x56\xae\x70\ +\x7f\x34\x53\xfe\xd1\x4c\xb1\x70\x21\x97\xca\x2c\xd4\x6b\x35\xdf\ +\x1a\x99\x92\x4d\x16\x44\xa5\xfc\xf4\x4f\x62\xe2\x61\x14\x61\x3e\ +\x8b\x88\x19\xe2\xe7\xf1\x08\xb4\x48\xed\x14\x95\xd1\x0b\xaa\x45\ +\xc9\x57\x65\xf9\x87\xef\x7e\x48\xd9\xec\x91\xf9\xa0\x7b\xaa\x4c\ +\x01\xe8\x53\x22\xd2\xfb\x6a\x65\xa5\xe2\xa1\x65\xd6\x76\xdc\x2c\ +\xe7\xd6\x93\x64\xda\x38\xbd\xfb\x68\xc3\xed\x19\x4c\xd3\x5e\xe7\ +\xb2\x31\xb8\x24\x46\xa6\xcd\xdd\x3a\x57\xeb\x6d\x13\x20\x6d\x81\ +\xd1\x7a\x7e\x74\xfa\xe8\xfc\x1f\x56\x0e\x86\x1f\x5f\x79\x73\x72\ +\xeb\xfb\x8b\xe3\xb1\x08\xf8\x0b\xc3\xf7\xed\x6f\x7f\x3b\x46\xad\ +\xbe\x36\xee\xb6\xfa\xda\xa2\xde\x6a\x57\x1d\xac\xf5\xb4\x46\x21\ +\x1c\xb7\xa7\x9f\x58\xa0\x56\x77\xad\x81\x20\x39\x56\x2a\xa0\x00\ +\xfd\xb5\xb0\x7f\x94\x09\xf3\x59\x8a\xe3\x86\x4c\xe5\x8f\xaf\x7c\ +\x64\xdb\xba\xb3\x1b\x18\xda\x42\xb9\x60\x17\x4f\x1f\x03\xbe\x71\ +\x6b\xf3\x5e\xa3\x3d\xb0\x70\x3c\x68\x0b\xb3\x05\x77\x41\x65\x26\ +\xa2\xcf\xda\xa0\x6a\xfb\xc0\xfd\x33\x99\x03\x5a\x71\x1d\xcb\xbb\ +\x30\xc7\x77\x9f\xb9\x68\x9f\xde\xbe\x6e\x07\x5c\x4f\x6a\x72\x21\ +\x9b\xb2\xdd\xce\x28\x54\x6b\xf6\xfe\xf4\xfb\xdf\xff\xbe\xe0\x32\ +\xb1\xe6\xff\xbf\x07\x6d\x32\xca\xeb\x2f\xdd\xbf\x1a\x83\x83\x1e\ +\xaf\x79\xbf\x1a\x5f\x8d\xaf\xc6\x57\xe3\xab\xf1\xcb\xc3\xec\xff\ +\x00\xa0\xa1\xea\x83\x3e\xf3\xbe\x33\x00\x00\x00\x00\x49\x45\x4e\ +\x44\xae\x42\x60\x82\ +\x00\x00\x07\x52\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7\x6f\ +\xa8\x64\x00\x00\x06\xe7\x49\x44\x41\x54\x78\x5e\xdd\x9b\xdb\x6f\ +\x14\x55\x1c\xc7\x7f\xe7\xec\xad\xdd\x5e\xd8\x5e\x2c\x5d\x4a\xb7\ +\x2d\x95\x4b\x03\x7d\x90\x82\xc6\x0b\x86\xad\x31\x98\x80\x18\x0c\ +\x60\xf4\xc1\x4b\xe2\x83\x41\x83\x0f\xea\x93\x7f\x82\x1a\x0d\x46\ +\x5f\xd0\x10\x4d\x34\xb1\x9a\xa0\x4d\x6b\xe0\x41\x5a\xc5\x88\x91\ +\xd6\x88\x20\xb4\x29\x6d\x29\xa6\x2c\xad\xb4\x85\x76\x2f\xdd\xcb\ +\xcc\xf1\xfc\x66\xcf\x94\x4e\xbb\xbb\xdd\xcb\xcc\x74\x97\x4f\x02\ +\x7b\xce\xaf\xdb\xb0\x9f\xef\x9c\xdb\x4c\x29\x81\x7b\x84\x89\x4b\ +\x1d\xa5\x55\x84\xbe\x09\x04\x0e\xf3\xee\xe6\x78\x95\x8c\x12\xc2\ +\xce\x10\x60\x27\x68\xcb\xa1\xbe\x78\x4d\xcb\x3d\x11\x80\xfc\xcf\ +\x77\x0d\x32\x81\xd3\x84\x10\x21\x9e\x00\xc6\x3a\x89\x14\x7d\x83\ +\xb6\x3e\xff\xaf\xa8\x28\x14\x7c\x00\x71\x79\xd2\x43\x08\x34\x89\ +\x52\x52\x18\xb0\x29\xfe\xe7\xa0\xad\xe5\x50\xaf\x28\x01\x15\xaf\ +\x05\x49\x26\xf2\x08\x01\x52\x35\x31\xe5\x3f\x75\xbe\xfb\xe3\x27\ +\x45\xa9\x70\x03\xc8\x54\x1e\xf1\x4d\xcd\x82\x6f\x7a\xce\x01\x12\ +\xeb\x18\xf9\xe9\xb3\x06\xac\x15\x64\x00\x39\xc8\x2b\xed\xea\x35\ +\x25\x2e\x4f\xad\xeb\x43\x6c\x17\xdc\x1a\xa0\x83\x3c\x78\x6a\x5c\ +\x4a\x3b\xc6\xa0\xcd\xa2\xb4\x0a\x04\x3d\xe5\x11\x4a\x20\x5a\x30\ +\x01\x04\xb9\x3c\xd5\x51\x5e\x50\x52\x10\x53\x00\xe5\xed\xfa\xcb\ +\xf3\xa3\x01\x0b\xe6\xfd\x22\x68\x94\xbc\x02\x3f\x22\xe6\x75\x00\ +\x86\xca\xc7\x19\xcc\xdb\x00\x4c\x90\xe7\x73\x80\x74\xe4\xe5\x1a\ +\x60\x86\x3c\x63\xfc\xea\x57\x94\xb6\xe5\xdd\x08\x30\x49\x7e\x94\ +\x32\xb6\x87\xba\xf7\x04\xf2\x2a\x80\xb8\x3c\x98\x21\xef\xa5\x5b\ +\x0f\x8e\x61\x3f\x6f\x02\x60\xc3\x9d\x9e\xb8\x3c\x31\x4d\x1e\xc9\ +\x8b\x35\x00\xe5\xa5\x70\xa4\xd7\x6c\x79\x64\xd5\x03\x58\x4d\x79\ +\x64\x55\x03\x58\x6d\x79\x64\xd5\x02\x60\x7d\x1d\x9e\xc0\xe0\x50\ +\x6f\x6c\xec\x46\x93\x74\xc7\x0f\xc4\x6e\x05\xeb\xda\x6a\x70\x6c\ +\x69\x04\x6b\x5d\x8d\x78\x97\x16\x8d\x7c\x39\x97\x5f\xbb\xb2\x7c\ +\x84\xcb\x3b\x93\xc8\x23\xab\x12\x80\xef\xd5\xa7\x9b\x88\x3f\xfc\ +\x93\xec\x0f\x26\xbc\xf2\xb6\x06\x37\x94\xed\x7b\x1c\x6c\x8d\xeb\ +\x44\xc5\x18\x79\xc4\xf4\xbb\xc1\x9b\x2f\xec\xdd\xc0\xa6\x67\x7f\ +\x66\x91\x88\xf2\x44\x26\x11\x32\x1f\x11\xa1\xbe\xcb\x00\xd1\x18\ +\xd8\xef\xaf\x57\xc4\x8d\x90\x47\x4c\x0d\x00\xe5\xe5\xb9\xb9\x5e\ +\x60\x72\xbd\x28\xa5\x24\x7a\xed\x06\xf8\x7d\xb7\xc0\x57\x55\xc9\ +\xc7\x2a\xd1\x5d\x1e\x31\x2d\x00\xe5\xca\xfb\xe7\x7a\xb8\xbc\x47\ +\x94\xd2\x82\x4c\x4e\x03\x91\x19\x94\xb5\x6c\x48\x43\x9e\x71\x79\ +\x48\x5b\x1e\x31\xe5\x20\xa4\xca\x33\x39\x33\x79\x95\xb2\x0b\x03\ +\x50\x1b\x0c\x88\x5e\x62\xb2\x91\x47\x0c\x1f\x01\xb9\xca\xab\x48\ +\x7c\x24\x14\x3f\xb8\x4d\xf4\xb4\xa0\xbc\xc5\x61\xdf\x6d\xdf\x7c\ +\xe0\xba\x28\xa5\x8d\xa1\x23\x40\x2f\x79\x24\x3a\xe6\x83\xd8\xf8\ +\xa4\xe8\xdd\x45\x95\x27\xcd\xfb\x33\x96\x47\x0c\x0b\x40\x4f\x79\ +\x95\xf0\xc0\x35\xd1\x8a\x93\xab\x3c\x62\xc8\x14\x40\x79\x3e\x68\ +\x7b\x6c\x9e\x5a\x8f\x6d\x5d\x0d\xd0\x92\x62\x90\x43\x61\x5e\x92\ +\xc4\x3b\xb2\x83\x96\x39\xa1\xa8\x75\xa3\xd2\xd6\x43\x1e\xd1\xfd\ +\x20\x14\x3a\x7d\xac\x89\xc4\x58\x2f\x3f\xc4\x78\x80\x2e\x1a\x60\ +\x92\xcc\xaf\xe0\x28\x04\x7a\xfb\x94\xed\x2d\x1b\x1c\x5b\x9b\xc1\ +\xf5\xf2\x7e\x6c\x8e\x50\xbb\xcd\x9b\xab\x3c\xa2\xeb\x08\x60\x97\ +\x3a\x3c\x64\x4d\x79\x8f\xa5\x72\x4d\x23\xee\xdb\x1a\x28\x01\x6b\ +\x4d\xa5\xb2\x90\xf1\xaf\x43\xe4\x2a\xff\xec\x3c\x94\x4c\x70\x6c\ +\xf4\x80\xa3\xa5\x69\x84\x4a\x92\x97\x6c\x79\x36\x67\x79\x44\xb7\ +\x00\x50\x5e\xa2\x96\x1e\x42\x09\x1f\xfe\xa9\xb1\xad\xbb\x8f\x9f\ +\xf9\x9b\x20\x74\x71\x48\x39\xed\xa5\x8b\x73\xd7\xf6\x11\x7b\x4d\ +\x85\x97\x6c\x3b\xac\x8b\x3c\xa2\xcb\x22\xb8\x20\x4f\x60\x45\x79\ +\x95\xff\x1c\x0e\x98\x7c\x6a\x17\x30\x9b\x55\x54\x52\x43\x4b\x9d\ +\xa3\xce\x4d\xeb\x75\x95\x47\x72\x0e\x20\x1b\x79\xf5\xc6\x26\x5a\ +\xe5\x82\x68\xfb\x43\xa2\x9a\x1c\x42\xe9\x75\x66\x75\x3c\x41\x76\ +\xbc\xa4\xab\x3c\x92\xd3\x14\xc8\x45\x1e\xa9\xc2\xb3\x7d\x6b\x33\ +\x44\x86\xae\x83\x7c\x3b\x5e\x5b\x0a\xca\x93\xd2\x32\xaf\xfb\xab\ +\xae\x51\x51\xd2\x95\xac\x03\xd0\x43\xbe\x01\xcf\xf6\x7c\xad\xc4\ +\x6d\x72\xfe\xaf\x41\xa5\xbe\x18\x55\xbe\xf6\xeb\xee\x11\x51\xd2\ +\x9d\xac\xa6\x80\x6e\xf2\x02\x5c\x10\x89\xc3\x2e\x7a\x71\x18\xbf\ +\x2b\xb6\xd8\xac\xaf\x19\x29\x8f\x64\x1c\x80\xde\xf2\x0a\x16\xaa\ +\xec\x0c\x2a\x28\x8f\xaf\xb1\x70\xf8\xf3\xf1\x7d\x0f\x6f\x51\x8a\ +\x06\x91\x51\x00\xc1\x9c\xe5\x9d\xcb\xe5\x05\x7c\x95\x57\x5e\x55\ +\x79\x9c\x19\xfc\x6f\x37\x01\x7a\xc6\xc8\x10\xd2\x0e\x00\xe5\xed\ +\x39\xcb\x57\x28\xed\x44\xc8\xe1\xc8\x12\x79\x15\x63\x43\x48\x2b\ +\x00\xa3\xe5\x41\x96\x21\x3a\x3e\x99\x40\x5e\xc5\xb8\x10\x56\x0c\ +\xc0\x70\x79\xce\xfc\xc5\xab\x12\x0b\x84\x58\x62\x79\x15\x63\x42\ +\x48\x19\x80\x19\xf2\xb1\xa9\xdb\xb1\xd9\xef\xcf\x60\x33\x8d\x2d\ +\x59\xff\x10\x92\x06\x60\x96\xfc\xf4\xa7\xdf\x02\xf3\x87\x32\x38\ +\x8f\xe8\x1b\x42\xc2\x00\xcc\x90\x67\x0c\x46\x66\xbe\xe8\x3a\xce\ +\x66\xfd\xe9\xdd\x0c\x68\xd0\x2f\x84\x65\x01\x98\x25\x1f\x91\x25\ +\x6f\xed\xf1\x93\x47\xf8\xca\xff\x81\x28\x67\x88\x3e\x21\xf0\x75\ +\xe7\x2e\x66\xca\x3b\x17\xdd\xd5\x8d\xef\x7b\xec\x7d\xfe\x41\xde\ +\x12\xdd\x0c\x61\x3e\x06\x72\x7b\x5d\xd7\xb9\x01\x51\xc8\x88\x85\ +\x00\xe4\xa1\x93\xf5\xb7\xef\x04\x7a\x83\xe1\xd8\x86\x68\x4c\xe2\ +\x87\x33\x02\xc5\x0e\x1b\x94\x3b\x8b\xc0\xca\x4f\x6a\x89\xd0\x43\ +\x5e\x65\xa5\x10\xf8\xf7\xbe\x0b\x84\x2c\x7f\x2a\xca\xa1\x32\xf8\ +\xdc\x3f\x9e\xed\x16\xdd\x8c\x50\x02\xe8\xeb\xfc\xc8\x63\xb5\x5a\ +\x7b\xa2\x31\x79\xd9\x95\x27\x7c\x38\x54\x96\x15\x83\xbb\xaa\x1c\ +\xec\xd6\xbb\x6b\x95\x9e\xf2\x2a\xa9\x42\x90\x18\xdd\x54\xdf\xfd\ +\xcb\x90\xe8\xea\x06\x3d\xfd\xe5\x7b\x25\x32\x23\xa7\x12\xc9\x23\ +\x8c\x7f\xf2\xa9\xd9\x20\x5c\x19\x9b\x80\x99\xb9\x90\x52\xcb\x46\ +\x9e\xda\xe8\xee\x54\xf2\x48\x5d\xd7\xaf\x6f\x67\xbf\x26\x64\x07\ +\xad\xa8\xb0\x1f\xe5\x57\xb9\x45\xf4\x93\x22\xc9\x0c\x46\x6f\x4e\ +\xc3\xf0\x8d\xa9\xac\xe4\xe9\xc6\x03\x9a\xdf\xd4\x48\x86\xd9\x21\ +\x50\x7e\xfa\x7e\x4e\xb4\x15\x94\x2b\x3e\x33\x07\x81\xe0\xbc\xa8\ +\x68\xb9\x13\x98\x57\xa6\x85\x11\xf2\x2a\x66\x86\x40\xb9\x8c\xe6\ +\xf7\x6c\x06\x86\xc7\xe1\x5c\xff\x00\xf4\xfc\x76\x11\x7e\xef\x1f\ +\x4c\x1a\x04\xae\x09\x2b\x30\x9c\x8d\xbc\x8a\x59\x21\x50\x7e\x95\ +\x16\x76\x02\x24\xcc\xef\xca\x54\x6e\xcd\xcc\xc2\xd9\x3f\x2e\x2b\ +\x23\x62\x31\x38\x4a\x70\x1d\x48\xc1\x30\xb1\x52\x6f\xb6\xf2\x2a\ +\x66\x84\xc0\xf7\x37\xa6\x79\xd6\x56\x53\xad\xbd\x5f\x8f\xf1\x2d\ +\xf1\xfc\x85\xa1\x65\x23\x61\x9a\x2f\x88\xb1\xc4\xcf\xf5\x75\x91\ +\x57\x31\x3a\x04\x9c\x02\x3d\xa2\xad\xe0\xae\xa9\x84\x0a\x57\xa9\ +\xe8\xc5\xc1\x10\xfe\xbe\xa2\xfd\xa9\x33\x8e\x82\xd9\xe5\xd3\x43\ +\x57\x79\x15\x0c\x61\xe2\x66\x40\xfb\x83\x41\x9d\xa0\x16\xb0\x9c\ +\x10\x6d\x05\xbe\xbe\x41\x5b\x6b\x33\x14\x17\x69\x9f\xd1\x4d\xf1\ +\xe9\xb0\x74\x14\x84\xc2\x51\xd1\x52\x30\x44\x5e\x65\x47\x7f\xbf\ +\xe6\x1f\xd3\x0b\xba\x7d\xff\xeb\xe7\xf9\xd5\xd4\x9c\xa2\x8a\x1c\ +\x76\x78\x74\x67\xcb\xb2\x91\x30\xaf\x15\x56\xb6\x46\x84\x01\x33\ +\x54\xde\x48\x94\x33\x2e\x25\xec\x08\x7f\x99\xc6\xb6\x0a\x86\xf0\ +\x48\x5b\x8b\x32\x1a\xd6\xbb\xab\xa1\xb9\xd1\x0d\x95\x4b\x02\xb1\ +\xf1\x93\x21\xca\x53\xab\xa5\x20\xe5\x91\x85\x1d\xa0\xef\x87\x63\ +\xed\x8c\x00\x8e\x84\xa2\x78\x65\x65\x9a\xeb\xaa\x86\x5d\xe5\xce\ +\x82\x95\x47\x16\xee\x72\x76\x3c\x73\xf4\x0c\x61\xb0\x97\x37\x35\ +\x23\x21\x19\x76\x9b\x65\xd8\x65\x2f\x6c\x79\x44\x73\x9b\xa7\x84\ +\x00\xf2\x03\x4b\xd7\x84\xa5\xf0\xaf\x5f\x89\x46\xa3\xed\xb4\xb5\ +\xb0\xe5\x11\xcd\x21\x68\x31\x7f\x76\x7e\xb2\x53\x02\xe9\x15\x2e\ +\xeb\xe5\x6f\x6b\xe2\xbb\x03\x6f\xb2\x41\x1e\xd9\x37\x33\x33\x91\ +\x63\x7b\x5e\x7c\x27\xf5\x7f\xdb\x2a\x08\x00\xfe\x07\x67\xd1\x50\ +\x78\x73\x48\xdf\xa1\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\ +\x82\ +\x00\x00\x12\x94\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x04\x67\x41\x4d\x41\x00\x00\xb1\x8f\x0b\xfc\x61\x05\x00\x00\x00\ +\x09\x70\x48\x59\x73\x00\x00\x12\x73\x00\x00\x12\x73\x01\x8c\x22\ +\xb9\x07\x00\x00\x12\x29\x49\x44\x41\x54\x78\x5e\xed\x9d\x0b\x7c\ +\x14\x45\x9e\xc7\xab\x67\x7a\x66\x92\x4c\xde\x6f\x86\xf0\x0c\x04\ +\x79\x0a\x11\xe4\x21\xc8\x43\x5e\xc2\x82\xba\x80\xe0\xb2\xa2\xa7\ +\xe2\xde\xae\x77\xab\xa7\xa2\xb2\xee\xde\x80\xae\xae\x72\x28\x7e\ +\x4e\x94\x45\x56\x3e\xec\x67\x17\x4e\x11\xbc\x8f\x08\x08\xac\x3c\ +\x22\x1e\x2f\x21\x21\x80\x0b\x84\x04\x13\x20\x24\x64\x48\x42\x26\ +\x93\xd7\x64\x1e\x57\xff\xee\xea\x99\xee\x9e\xee\x49\x80\xee\x88\ +\x4c\x7d\xc3\xbf\xab\xea\x5f\x55\x3d\xa1\x7f\xff\xaa\xae\xee\xe9\ +\x99\x20\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x42\xa1\x50\x28\x14\ +\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x72\x9b\xc2\x90\x54\x13\xe6\ +\x6c\xdc\x68\x4c\xfa\xb6\x60\xdc\x85\x8a\x8a\x2c\xe2\x0a\x8b\xc5\ +\x6c\xb8\xf4\xc5\xfa\xfa\x7d\x08\x7d\xe6\x25\x2e\x45\x5e\xb1\xbf\ +\x99\x73\xf2\x6c\xc9\x48\xaf\x57\xda\x2c\x31\x3e\x1e\x1d\xcd\xdb\ +\xfe\x49\x71\x71\x71\x0b\x71\x29\xf2\xfc\x2b\xf6\x9c\xb3\xa5\x97\ +\x42\xfa\xa7\x24\x26\xa2\xc3\x7b\xcf\xe0\xfe\x3b\xc2\xf6\x7f\xe6\ +\x79\x7b\x4e\xe9\xe5\xd0\xfe\x69\x29\x29\xe8\x60\xe9\xf7\x9f\x14\ +\xef\x08\xdf\x1f\xf5\xea\x65\x79\x70\xe4\xc4\x79\xcd\xcd\xcd\xc4\ +\xa1\x8e\xd1\x68\x44\xdd\x6d\x59\x07\x3f\x78\x77\x69\x11\x71\xe9\ +\x8a\xa6\x01\xd0\x6f\xe8\xe8\xad\xa7\x4b\xca\xa7\x33\x4c\x7b\x77\ +\xeb\x47\x49\x71\x31\xa7\xaa\xbb\xa7\x0e\x41\x79\x79\x1e\xe2\x94\ +\x30\x6c\xdc\xd4\xc7\x4e\x17\xfd\xb0\xae\xb1\xb9\x95\x78\xc4\xf8\ +\x91\x89\x31\x54\x75\xe9\xd6\x75\x54\x71\xfe\xde\x12\xe2\x94\xd0\ +\x73\xe0\x88\xc7\x2a\x1c\x35\xeb\x5a\xdc\x4a\xbb\xf7\xa3\x18\xb3\ +\xa9\x2a\xbb\x4f\x8f\xe1\x85\x79\x3b\x4b\x89\x53\x82\xed\x8e\xdc\ +\xc7\x6a\x6b\x5d\xeb\x5a\x5a\x95\xfb\xc7\x5b\xa3\xaa\xc6\x8e\xba\ +\x77\xf8\x17\x9f\xae\x56\xec\x6f\xb1\x74\xc9\xf6\x44\x1b\x0e\xf8\ +\x0d\x86\xf4\xf6\x1e\x6e\x8b\x89\x45\x49\x49\xb1\x8f\x5f\x3e\x93\ +\xff\x57\xe2\xd2\x0d\x23\x49\x6f\x9a\x5f\x2f\x5e\x3a\x76\xc7\xae\ +\xbc\x37\x91\xd9\x82\x90\x01\xef\xb6\x9d\xd6\xd4\xea\x4d\xbf\x33\ +\x36\xce\x75\xa5\xbc\xec\x00\xd9\x95\x04\x53\x4c\xea\xae\xab\xae\ +\x66\xab\x52\x5f\x30\x9f\xd1\x68\x8d\x36\xa2\x4e\xce\xea\xcb\x9f\ +\x91\x2e\x12\x58\x6b\xea\x2e\xa7\xdb\xa3\xda\xdf\x83\x0c\x56\x9f\ +\xab\xc1\xd4\x50\x57\xb5\x9d\x74\x91\x60\xc2\xfd\x5d\xad\x3e\xd5\ +\xfe\x6e\x1f\xb2\x7a\x5d\x75\xa6\x1a\xc7\x25\xc5\xfe\xe6\xe4\xf4\ +\xd5\xad\x26\xcb\xdd\x4a\x7d\xd5\xcc\x83\x03\xc5\xe4\x67\x46\x35\ +\xd5\x55\x2d\x27\xbb\xd1\x0d\x03\x49\x6f\x9a\xe2\xf3\x17\xd2\x99\ +\x1b\xd8\x1d\xcc\x16\xd7\x6a\xea\x1a\x48\x31\x84\xa6\x96\xe6\x46\ +\x92\x55\xa5\xbe\xb1\x49\x71\xf6\x00\x2c\x16\x73\x32\xc9\xaa\x12\ +\x15\x15\xad\xda\xc6\x6c\x36\xb5\xd9\x3f\x3a\x26\x4a\xb5\x8d\xb7\ +\x15\x9f\x36\xfc\x7e\x52\x6a\x3f\xcd\x1e\x1f\x9e\x31\xf4\x47\xb3\ +\x53\xc0\xa4\xb9\x4f\xce\xd9\xbd\x73\xcf\x46\xbf\xd9\x4c\x3c\x3c\ +\xe1\x5e\xc0\x8f\x0f\x4c\xac\xc1\x7b\x71\xd7\xaa\xf9\x4f\x8e\xc8\ +\x8e\xaf\x25\x6e\x09\xf3\x5e\xfd\x72\xd4\xe6\xff\xbb\xf0\xae\xd7\ +\x64\x32\x32\xb2\xbd\x41\x7f\x2b\xeb\x77\xbf\xfe\xab\x09\x0b\x9f\ +\x7b\xa8\xf7\x3f\x89\x5b\xc2\x82\xe5\x05\xbf\xd9\xb0\xf5\xc0\x02\ +\x9f\x4a\xff\x78\xb3\xc1\xfd\x5f\xcf\x4d\x5f\xb8\x70\x72\x27\xc5\ +\xfe\xf3\xdf\x3a\xf2\x9b\x4f\x77\x7c\xa7\xda\x3f\x39\x8a\x75\xaf\ +\x7d\x75\xc2\xcf\x66\x8e\xec\xae\xf8\xfb\xbf\xf4\x97\xe3\xa3\xde\ +\xff\xf4\xd0\xbb\x2d\x7e\x83\x31\xdc\xa9\x51\x1e\x22\xd1\x2c\x8b\ +\x1a\x2f\x7f\x1f\xee\xf0\x69\x82\x66\x2f\xa0\x14\x00\xfd\x92\x8d\ +\xab\x9f\x9b\x3b\xd8\x44\x8a\x21\x18\x8c\x26\x34\x63\x7c\x7f\x47\ +\x5a\xbc\x21\xec\x28\xdf\x7f\xd2\x91\x76\xf6\xdc\xc5\x18\x52\x0c\ +\x62\x60\xd0\xc4\x11\x7d\x1c\xdd\x33\x63\xc2\xf6\xcf\x2b\xac\x4c\ +\x3b\x57\x72\x59\xb1\xff\xe4\x51\x7d\x1c\x5d\xd3\xc3\xf7\xdf\x7b\ +\xbc\x32\xad\xe4\xbc\x52\x7f\x23\x9a\x32\xba\x8f\xa3\x4b\x6a\x54\ +\xd8\xfe\xc7\x4a\x5c\x69\x05\x85\xe7\x70\x7f\xf5\x99\x60\xd1\xc7\ +\xc7\x06\xd5\xb9\xd1\x50\x52\xbc\x3d\x02\xe0\xfe\x9c\xf8\xc5\xdb\ +\x3e\x98\x2b\x9d\x12\x28\x8a\x64\x3e\xb0\x76\x4c\x55\xa3\x77\x22\ +\x29\x76\x58\x00\x68\xb6\x06\xa0\xfc\x34\xa1\x01\x10\xe1\xd0\x00\ +\x88\x70\x68\x00\x44\x38\x34\x00\x22\x1c\x1a\x00\x11\x8e\x66\x01\ +\xd0\xb3\x8b\xcd\x8d\x90\x8f\x94\x30\x3e\x1f\x8a\x4a\x48\x20\x05\ +\x4a\x5b\xc4\x59\xa3\xb9\xbb\xa2\x02\x31\x16\x13\x3e\x9e\xfa\xa3\ +\x59\x00\xac\x5e\xfe\xfa\x17\xbd\x7b\x66\x9d\x66\xb0\xf0\x8c\xdf\ +\x8f\x58\xaf\xe7\xf4\xb2\x67\x27\x1f\x21\xd5\x94\x36\x58\x30\x73\ +\xe8\xe7\x26\x5f\xab\x9b\x41\xf8\xd8\xe1\x81\x94\x14\x1f\xfd\x16\ +\xa9\xd2\x15\x4d\x6f\x34\x7c\xb8\x7e\x7d\xd2\xdf\x3e\xde\x70\x9f\ +\xdb\xd5\x84\x32\x7b\xf5\xd9\xbd\xf5\xe5\xec\x6c\xec\x9e\xc6\xd7\ +\x52\xda\x60\xfb\xb0\x67\xf6\xd6\xa4\xa7\xc6\xcf\xba\x78\xe1\xca\ +\xee\x93\xf9\x7b\xf2\x89\x5f\x57\x74\xbd\xd3\xe4\x2f\x5c\x0e\xb7\ +\x36\x69\x00\xb4\x8f\xed\xcc\x9d\x2f\x1e\x25\xf9\x0e\x83\x2e\x02\ +\x23\x1c\x1a\x00\x11\x0e\x0d\x80\x08\x87\x06\x40\x84\xa3\x79\x00\ +\xd8\xed\xf6\x28\xfb\x8a\x15\x89\xa4\x48\xb9\x4e\xec\xcb\x56\x66\ +\x92\x6c\x87\xa0\xe9\x55\xc0\xe4\x07\x1e\x7e\xe1\xdb\x83\xf9\xcf\ +\x5a\x4c\xa6\x78\xe4\x67\x5e\xaf\xf9\xea\x89\x3c\xec\xa6\x57\x01\ +\xed\xa0\xcc\xd1\xf0\x75\xee\x13\x1b\x5f\x36\x9b\x8c\x33\x5b\x5b\ +\x3d\xa7\x6c\xb6\x4e\xbf\x38\x79\x68\xf7\x49\x52\xad\x1b\x46\x92\ +\xde\x34\xbf\x7f\xfb\xbd\xde\xff\xf3\xd9\x96\x2f\x9b\x91\x31\xa1\ +\xd9\xe7\x8f\x6a\x71\xbb\x27\xb7\xb2\x09\xa7\x26\x0c\x4a\x89\x26\ +\x4d\x28\x61\x98\xbd\x64\xff\xec\x33\x97\xaa\x1f\x70\xb9\xbd\xa8\ +\xc9\xe3\x4f\xf7\xb6\x34\x8f\x6c\xbc\x56\xb5\x9a\x54\xeb\x86\x66\ +\xa7\x80\xa3\xf9\x27\x07\xbb\x5b\x82\x8f\x6e\xfb\x59\x13\x2a\x38\ +\x58\x68\x25\x45\x4a\x1b\x9c\x2a\x2a\xb3\x8a\x1f\x18\x6b\x74\xfb\ +\x06\x93\xac\xae\x68\x16\x00\xfc\x47\x26\xe4\x67\x14\xd1\x7b\x03\ +\x94\x5b\x12\x7a\x15\x10\xe1\xd0\x00\x88\x70\x68\x00\x44\x38\x9a\ +\x05\x40\x82\x35\xae\xd1\x2f\x3e\xe7\xc3\x5b\xc2\xd1\xf4\x02\xa0\ +\xbd\x44\x59\xcc\x78\x09\x15\x5c\x43\x45\x5b\x54\x3f\x4e\xa1\x29\ +\x9a\x05\xc0\xa6\xb5\xef\x6d\x33\x1b\xd8\xe3\x20\x3c\x58\x9c\x85\ +\x69\xfc\xd3\xb3\xf7\x29\x7e\xde\x8f\x12\xca\xcc\x31\x7d\xf7\x98\ +\x84\xa5\xb4\xcf\x87\xdc\x0d\x8d\x7f\xe2\x0a\x3a\xa3\xd9\x7d\x00\ +\x20\x39\xb6\xd3\xfa\x2e\x5d\x32\x2c\xbe\x56\xef\x41\x5b\x66\xea\ +\xbc\x25\x8f\x0e\x80\x29\xa0\x37\x5f\x4b\x09\xc7\xfd\xc3\x6d\x3b\ +\xf7\x9e\x6a\xdd\x7c\xa1\xac\xbc\xaa\x6f\x76\xd7\xbf\x5f\x3a\x77\ +\xec\x6d\x52\xa5\x2b\xf4\x79\x80\x5b\x07\xfa\x3c\x00\xa5\xe3\xa1\ +\x01\x10\xe1\xd0\x00\x88\x70\x68\x00\x44\x38\x9a\x07\xc0\x6f\x17\ +\xbf\x91\x31\xef\xb7\x8b\x33\x48\x91\x72\x9d\x2c\xf8\xf7\x17\xb3\ +\xed\xf6\x95\xb1\xa4\xa8\x3b\x9a\x5e\x05\xe4\x8e\x9e\x6c\x3f\x73\ +\xf6\xfc\x4b\x3e\xbf\x0f\x21\x8f\x6f\x59\x53\xde\xbf\x6d\xc3\x6e\ +\x7a\x15\xd0\x0e\x4e\xfc\x50\xbd\x6f\xc4\x53\x9f\x2e\x61\x59\x76\ +\x3c\xcb\x1a\xaf\x5a\xac\x51\xf7\x57\x9e\x2d\xd0\xfd\xaa\x40\xb3\ +\xfb\x00\xcf\xdb\x97\xdf\xf1\xe5\xf6\x9d\x9b\xdc\x06\xd6\xe4\x65\ +\x8c\x26\xaf\xdf\x3f\xae\xd6\x6d\x3e\x3d\xf5\xae\x4c\x0b\x69\x42\ +\x09\xc3\x2c\xfb\xbe\x39\xa5\x35\x0d\x53\xdc\x7e\x06\x35\x7b\xfd\ +\x31\xac\xdf\x37\xb2\xd9\xe9\x58\x45\xaa\x75\x43\xb3\x53\xc0\xc9\ +\x33\xa7\x07\x7a\xbd\xa2\x77\xb4\x59\x13\x3a\x57\x78\x26\x8a\x94\ +\x28\x6d\x50\x5c\x56\x19\x05\x37\x51\x05\xdc\x5e\x66\x20\xc9\xea\ +\x0a\x5d\x04\x46\x38\x34\x00\x22\x1c\x1a\x00\x11\x8e\x66\x57\x01\ +\xf4\x5b\xc2\x82\xbc\x74\x20\x76\xe9\x5e\xe7\x48\x64\x60\x94\xbf\ +\x16\x0e\xce\xf5\xdc\x47\xc1\xb9\x77\x4e\xe1\x2d\x74\x3f\xf7\x13\ +\x94\x43\x9c\xe7\xf1\xb9\xae\xa2\x77\xe6\xe4\x4c\x1b\x77\x67\x8f\ +\xaf\x88\x4b\x13\x34\x9b\x01\x12\x12\x62\xea\x25\xcf\x03\xf8\x7c\ +\xc8\x6c\x8d\xcc\x67\x42\x0d\x06\x06\x59\x53\x33\xb0\x65\x2a\x5a\ +\x6c\x1a\xa4\xb8\x1e\xd2\x74\x1b\xb6\xce\x28\x36\x3d\x0b\x1b\xa4\ +\xf2\x3c\xb6\x8c\x2c\x64\xb1\xc6\x69\xfb\xd6\x2d\x41\xb3\x00\xd8\ +\xf4\xd1\xfb\x3b\x2c\x26\xd3\x61\x78\x2f\x1b\xa2\x3a\x31\xc6\xe4\ +\x5c\xb9\x68\xfc\x37\xa4\x3a\xa2\x20\x8f\x44\x40\x8e\x2b\x87\x22\ +\xf2\xab\x35\x91\x21\xbe\x42\xd0\x12\x4d\xd7\x00\x19\x31\xad\xe3\ +\xee\xec\x9f\xf3\x9a\x2d\x35\xf5\xb5\x9e\x39\xb6\xae\x9d\xd3\xac\ +\x1d\xf2\x2d\x17\xb7\x24\x20\x18\xbe\xa6\xe7\xd3\x30\x06\x70\x79\ +\xbc\x09\x98\xe0\x13\x99\x4e\x68\x1a\x00\x65\x65\x65\xcd\x05\x79\ +\xdb\xec\xe5\xa7\x0f\xda\x8f\x7d\xfd\x75\x1d\x71\x47\x24\x41\xed\ +\xf8\xb3\xbb\xd4\x18\xac\xb3\xdc\x0f\xdf\x0d\x22\x98\xd8\x1f\x34\ +\x3d\xa0\x57\x01\x3a\xc0\x89\x15\x58\xc3\x49\x17\x73\x01\x24\x5f\ +\x1c\xad\x26\xb1\x5e\xb2\x07\xa1\x01\xf0\x63\x10\x38\xa1\x0b\x29\ +\x04\x03\x98\x5c\x70\x95\xe0\xd1\x10\x1a\x00\x3a\xa0\x76\x1a\xe7\ +\xa7\x7d\xfc\x83\x47\x3f\xef\x93\x4f\xf7\x42\x19\xff\x40\x5b\xa1\ +\x3d\x97\xea\x03\x0d\x80\x8e\x44\x32\xed\x87\x03\xb7\x83\xb6\x5c\ +\x7b\x21\xd5\x07\xcd\x03\xe0\x67\x8f\x3e\xdd\xf5\x17\x0b\xff\xa3\ +\x43\xde\xc8\xb8\x55\xe1\x46\xab\xea\x90\x05\x31\xe5\x95\x6d\x8f\ +\x6f\x98\x55\xa4\x7f\xb2\x4a\x1b\x34\x0d\x80\x1e\x03\x86\x2f\xdb\ +\xb9\x75\xe7\xb9\xcf\xff\x77\xcb\x09\x5b\xf6\x90\x0d\xc4\x1d\x71\ +\x08\x12\x83\x68\x21\x06\xb7\x49\xf0\xe5\x21\x5f\x26\xd3\x3b\x94\ +\x7d\x90\x8a\xda\xc9\x8d\xdb\xb3\xf6\x68\x16\x00\xff\xba\xd8\x3e\ +\xe0\x42\xf9\x95\x45\x1e\x53\x94\xb9\xc5\xc0\xa2\x8a\x5a\xe7\x23\ +\x4f\xaf\x38\x3c\x96\x54\x47\x14\x20\x16\x88\xa6\x88\x64\x36\x87\ +\x82\x7e\xd3\x7b\x7b\xd0\x2c\x00\x4a\xce\x5f\xea\x0b\x91\x1c\x80\ +\x65\x51\x79\x71\x69\xc7\x7c\xbe\xe9\x16\x03\xb4\x67\x54\xde\x07\ +\x08\x10\x52\x2d\x0b\x04\x2e\x8a\xf8\x2c\xd0\xc6\xde\x6e\x18\xba\ +\x08\xd4\x89\x70\x37\x74\x38\xc3\x7a\x73\x29\x9e\x2a\x24\xe5\x40\ +\x3d\xf6\x73\x3e\xbe\x9e\xdf\x68\x0f\x0d\x80\x1f\x0d\xa2\xa8\xea\ +\x0a\x9f\x04\x10\x69\xa6\x93\xfe\x34\x00\xf4\x40\x2c\x9c\x40\x40\ +\xc8\x40\x06\x04\x0e\x38\xf9\x14\x3c\x24\x0f\x5b\x2e\x34\x60\x23\ +\x54\xeb\x00\x0d\x00\x3d\x10\xe9\x2a\xac\xf4\x85\x32\xe0\x83\x15\ +\x3f\x34\x82\x20\x80\x04\x46\x3b\x4e\x7d\x30\xe7\x63\xb8\x76\x78\ +\xc3\xa7\xdc\x3f\xce\xf4\x40\xb3\x00\x48\x4b\x4e\xaa\x95\x7c\x27\ +\x50\x04\xff\xbd\x00\x4e\xdc\x00\x20\xaa\x78\x9a\x67\xf0\xac\x1f\ +\xf4\xf1\x2d\xf9\x2d\xef\x11\xda\x92\x54\xd8\x95\x4e\x11\xa0\x59\ +\x00\x6c\x58\xb5\xfc\xeb\xc4\xf8\xd8\x3c\xe4\xf5\x20\xe4\xf5\xa2\ +\xcc\xc4\xd8\xda\x8f\x5e\x9e\xb8\x8f\x54\x47\x18\x82\x88\xea\x08\ +\x7a\x4a\x45\xe7\xfd\x82\x71\xe8\x78\x17\x10\xd0\xf4\x14\x30\xb0\ +\x47\xea\xc4\x7e\x7d\xb2\x67\x0f\xcf\x1d\xf4\x72\xb7\xc1\xd9\x9d\ +\x53\x12\x58\xd5\xbf\xe9\x7b\xbb\x23\x16\x52\x6a\xc1\xf9\x21\xb4\ +\x4e\x4a\xb8\x3a\xad\xd0\x34\x00\xf2\xf2\xf2\x3c\xdf\x1f\xd8\xb5\ +\xf9\xd0\x3f\x3e\x5f\x76\x68\xd3\xa6\x26\xe2\x8e\x3c\xb8\x93\xb7\ +\x1c\xc1\xc7\x8f\x68\x79\x0b\xe9\x69\x43\x20\xe8\x53\xaa\xd5\x02\ +\xba\x08\xd4\x91\xd0\xb5\x40\xb0\xcc\x5f\xe4\xf1\x6d\xe0\x47\xfe\ +\x87\xa9\x79\x44\x7d\x74\x8a\x00\x1a\x00\x3a\xc0\x3f\xe7\x0b\x90\ +\x6b\xf9\x80\xf1\x65\x1f\xde\x0a\x79\x5e\x64\xc8\xc3\x8f\xb8\xad\ +\xb8\x0f\xe4\xf4\x81\x06\x80\x5e\x84\x2a\x19\x30\x26\xe4\xb6\x1f\ +\x98\x92\x4f\x30\x21\x58\xb4\x87\x06\x80\x0e\x08\x62\x29\x89\x26\ +\xaf\xe3\x47\x3e\x2e\xc1\x3f\xc5\xb5\x83\xbe\xd0\x00\xd0\x09\xb1\ +\xd0\x62\x03\x84\x94\xbf\x6b\x42\x4e\x01\x5c\xc2\x8f\x74\x25\xf3\ +\xc1\x46\x07\xb4\x0d\x00\x63\xca\x84\x38\xdb\x1d\x0d\xa6\xe4\xec\ +\x86\x61\x63\xa7\xae\x24\xde\x08\x04\xd4\x6c\x9b\xf6\xb5\x6a\x7f\ +\xbb\x1b\x41\xb3\x00\x78\xf4\x99\x57\x52\x8c\x09\xf1\xbb\x5c\x1e\ +\x7f\x8c\x87\x65\x63\x8e\x9d\x3c\xfb\xcc\xd2\x8d\x65\xe3\x49\x75\ +\x44\xd1\xd6\xa2\x2d\xa4\x5e\x98\xfa\xe5\xee\xc0\x8f\x7e\x41\xa0\ +\x59\x00\x38\xae\x3a\x26\xf8\x7d\xfe\xc0\xa7\x97\xfc\xac\x19\x1d\ +\xc9\x3b\xa2\xc7\xa7\x99\x6e\x79\x0c\x44\x2d\x10\x4e\xc9\x40\x4e\ +\x3e\xcf\x8b\x1b\x78\x48\x14\xf7\xe3\xde\x3b\xe0\xea\x00\xd8\x11\ +\x59\x00\xe2\x36\x46\x96\x85\x9c\xa6\x68\x16\x58\xb7\xc3\x87\x43\ +\x1f\xd9\x1a\xb5\xb4\xce\x63\xc5\xc7\x9a\x3f\xfc\xb0\xe5\x0f\x10\ +\x39\x4c\xc2\xd1\x12\x6e\xcf\xe2\x06\x7c\x4b\x00\x7c\xf8\xa2\x0d\ +\x0f\xa9\x8a\xfa\x58\x64\xea\x7e\x0f\x0e\x04\xa1\x83\x14\x90\x58\ +\xb8\xee\xe7\x5f\x23\xf8\x4a\x8a\xe0\xfd\x38\x2f\xff\x80\x0c\x75\ +\x15\x25\x75\x4d\xee\x7a\x6e\xed\xc0\xbd\x30\xde\xc0\x6b\x08\xdd\ +\x49\x2a\xd4\x0b\xa3\x1b\xca\x5c\x1e\xff\x72\x2d\x2d\x8d\xe8\xd9\ +\xfb\x07\x96\xfc\xe1\xe1\xdc\xd9\x9c\x0b\x36\x5a\x70\xbb\x7c\x3a\ +\x78\xe8\x67\x7d\x97\x1a\x3a\x0f\xe5\x3e\xe0\xc9\x01\xd3\x33\x97\ +\x15\x1f\x2a\xe1\x88\x03\xb2\xa3\xcf\xa5\x90\xe3\x53\x9e\x60\xfb\ +\x60\xee\x7a\x91\xee\x51\x8a\x7c\xaf\xe2\x32\xc9\xe3\x40\xa9\x77\ +\x54\xa0\x09\x99\x0d\x25\xd3\x86\xa4\x8e\x9c\x96\x9b\xe3\x80\x5a\ +\xcd\x4e\x01\xb7\x0b\x47\xe7\x9c\xb6\xb7\x5e\x3c\x82\x57\xdd\x70\ +\xbb\x06\x8f\x1d\x6e\x36\x00\x83\x71\x24\x98\xb8\x2c\xe4\xc5\x69\ +\x70\x1a\xe7\x8d\x4c\xf1\xd8\x42\xeb\x78\x4f\xa8\x4f\x6e\xe2\x52\ +\xf0\x75\x78\x03\xc4\x3e\x40\x9c\x47\xc8\xe9\xb8\x8c\xc6\xa7\xbb\ +\x24\xe2\x03\x34\x00\x14\x28\x98\x7b\xd6\xee\xbe\xf0\x1d\xbc\xa3\ +\x2d\x22\x78\x30\xd5\xe1\xdb\xf0\x62\x05\x91\x96\xe5\x23\x15\x10\ +\x8f\xd6\x70\xc8\xdb\x8b\x09\xfa\xc4\x7b\x81\x7c\x7d\x75\x05\x1a\ +\x97\xe6\x2a\x9e\x7e\x57\x0f\x89\xf8\x00\x0d\x00\x15\x8e\xe3\x20\ +\x68\x85\x20\xc0\x47\x10\x0e\xa2\x78\x14\x87\x9a\x30\x3e\x85\x69\ +\x5a\xda\x56\x5e\xe6\xdb\xc3\x8f\xdc\x2f\x2e\xcb\x7f\xe4\xf5\xea\ +\x06\x08\x79\xd7\xd5\x4a\x34\x36\xb5\xbe\x78\xc6\xd0\x9e\xa3\xa6\ +\xe5\xda\x24\xe2\x03\x34\x00\xc2\x70\x7c\xde\x59\x7b\xcb\x85\xa3\ +\xc8\xab\x70\x17\x46\x7a\xd3\x2e\x74\x44\xf2\x92\x71\x19\x05\xa0\ +\x3d\x16\x53\xb1\x4e\xdc\x8f\x6f\xa7\xb4\xff\xf0\xf0\xaf\xde\x50\ +\x5d\x89\xc6\xa4\x39\xb1\xf8\xd9\x8a\xe2\x03\xfa\x06\x80\xf1\xa7\ +\x1f\x5f\x85\x73\xcf\xd8\x7d\x97\x8e\x21\xee\x2b\xf0\xe0\xa8\x12\ +\xe3\x24\x11\x95\xa5\x86\xc7\xaa\x70\x6f\x1f\xc0\x29\x27\xb6\xcc\ +\x94\xf6\xc1\x3d\x5a\x0f\x79\xa8\x95\xd5\xb5\x6d\x78\x03\xff\xf0\ +\x3e\x1a\xab\xaf\xa0\xd1\x29\xce\xe2\xc9\xfd\x6d\xf7\xa8\x89\x0f\ +\x70\xbf\x83\x16\x28\x5d\x05\x18\x91\xdf\x03\x4f\x37\x93\xa2\x0c\ +\x06\xc5\x44\x99\xd1\xb0\x3e\xc9\x1f\xfd\xe3\x9d\x19\xeb\x88\x33\ +\x84\x2d\xdf\x96\x26\xfd\x6e\x6d\xe1\x9a\x73\x17\xab\x6c\xf2\x7b\ +\xe5\x06\x1c\x60\xc3\xfa\x76\xfd\x6e\xfd\x92\x99\x4b\xba\x26\x36\ +\xd7\x12\xb7\x84\x2d\xfb\x8a\x93\x16\xad\x3d\xb1\xa6\xb4\xa2\x5a\ +\xd6\x9f\x41\x2c\xee\x3f\xa8\x67\xf2\xb6\x43\xab\x1e\x7a\x83\x38\ +\x43\xd8\xb2\xef\x6c\xd2\x0b\x1f\x9f\x5a\x13\x3f\xf3\xd5\x6e\x8c\ +\xed\xae\xe0\xd5\x41\x00\xd8\x67\x5b\x3e\xa5\x36\x04\xf8\x9d\x02\ +\x97\x8b\x61\xda\x05\xc0\x6d\x02\xcd\x14\x5e\x03\x27\x8d\x35\x95\ +\xe8\x9e\xd4\xfa\x73\x53\x06\x74\x1a\x3d\xeb\x9e\x5e\x55\x7c\xbd\ +\x32\x6d\xbd\x5a\xbb\x51\x0a\x80\x76\xe1\x6d\x45\x83\xfb\xf5\x99\ +\x5d\xb0\xff\xab\xcd\xc4\x23\x21\xbd\xc7\xc0\x3d\x8e\x46\xf7\x78\ +\xee\xff\xa7\x00\xfc\x07\x6c\x71\x31\x6f\x5d\x2a\x29\x58\xcc\x7b\ +\xa4\xc4\x75\xca\xd9\xe3\xf2\x32\xaa\x77\x24\x19\x2c\x40\x4e\x56\ +\xc6\x9b\x67\x0a\xf6\xbf\x4a\x5c\x12\xb2\xfa\x0c\x2b\x2a\xaf\x75\ +\x72\x7f\xf5\x24\xf7\x57\xef\x20\x5f\x66\x2e\x17\x38\xca\x04\x94\ +\xf9\x51\x80\x57\xe7\xa6\xfd\x76\x8a\x0f\x68\x36\x47\x27\xc4\xc2\ +\xf7\x1b\xab\xa8\x14\x06\x86\x35\xa3\x38\x96\x19\x47\x8a\x21\x44\ +\x5b\x63\x55\xc5\xe7\xc0\xa3\xa7\xd2\xe9\xca\x26\xa5\x10\x2c\x51\ +\x31\xe1\x6f\x47\x1b\x0c\xa8\xca\x71\x4d\xf5\xcf\xda\xd4\x37\xb5\ +\x04\xea\xf2\x57\xbf\x80\x8c\x95\xf9\xf8\x74\x20\xbe\x3c\x10\xff\ +\x72\x20\x7e\xdb\xc7\x40\x98\x14\xc3\xb7\x14\x6a\xe5\xa9\x9c\xe0\ +\xbe\x60\xc1\x37\x26\xd5\xd9\x6e\xf1\x01\xcd\x02\xa0\x7f\x56\xe2\ +\x66\xb3\x89\xad\x02\x41\xe0\xa9\xd7\xf6\x18\xde\x20\xd6\xef\x41\ +\x3e\x6b\xc2\x26\xb2\x9b\x10\xae\x55\xd7\xac\xe2\xd6\xbe\xb2\xbe\ +\x42\x7f\xe4\xf1\xa0\xec\x4e\xa9\x3b\x48\xf3\x10\x9c\x75\xd7\x70\ +\x7f\x8c\xac\x6f\xa0\x7f\x6b\x2b\xea\xd5\xbb\xb3\x6a\xff\xe4\xb8\ +\xe8\x1d\xe2\xd7\xcf\xff\xe8\x45\x64\xbc\x52\x80\x5f\x16\xee\x13\ +\xc0\x81\x17\x56\xe6\xbc\xac\xca\x2b\x75\xa1\x8e\x37\xbc\x33\x92\ +\x4a\xfd\xbc\xa9\xed\x07\xca\xa2\xf6\x78\x13\xf4\x33\x9c\xf8\xe3\ +\xd2\x60\xe4\xdb\xda\x2d\x3e\xc0\x1d\x1b\xad\xe8\x37\x62\x72\xaf\ +\x8a\x1f\x4a\xff\xd0\xe4\x67\xb2\x88\x2b\x2c\x71\xd1\x66\x94\x9e\ +\x92\xb8\xec\xfb\xfc\xfd\x3b\x89\x4b\x09\xa6\x73\xf7\x41\xaf\xd7\ +\x34\xb6\x8c\x84\xff\xb0\x18\x13\x9e\x8a\x3b\xa5\x25\x6c\x28\x3a\ +\x71\xe8\x63\xe2\x52\x82\x19\x90\x3b\x76\x5d\xc9\xa5\xca\x2c\x79\ +\x7f\xb3\x91\x45\xdd\xbb\xa4\x6d\x38\x71\x64\x5f\xd8\xfe\x7d\x87\ +\x8c\x5e\x57\x5a\xee\x90\xf4\x1f\xf4\xeb\x77\x27\xb8\xd3\x06\x23\ +\x96\xd5\xf7\xed\x0e\x90\x9c\xbb\x17\x05\xc1\xaa\x08\x83\x9c\xdc\ +\x1d\x3e\x57\xd1\xa4\x7e\x99\x63\xae\x47\x7c\x40\xd3\x00\x88\x34\ +\xee\xfe\xcf\x6d\x7e\x77\x7a\x47\x04\x81\x9a\x50\x82\xf8\x0d\x45\ +\x0f\x0d\xcb\x18\x33\x65\xf0\xf5\x89\x0f\xd0\x00\xb8\x49\xee\xb6\ +\xe3\x20\xc0\x33\x81\xd1\xa8\x16\x04\x62\xf9\x84\x39\x44\x7e\xd8\ +\xd5\x25\x56\x07\x8b\x7f\xb5\x1c\x4d\xb2\x35\x17\x3d\x70\x57\xfa\ +\x0d\x89\x0f\xd0\x00\xd0\x00\x08\x82\x96\x54\xb5\x99\x40\x4d\x5c\ +\xfe\x7c\xce\xd7\x88\xeb\x05\x7f\x38\x69\x60\xe4\x97\xa3\x29\x9d\ +\x9b\x8b\x66\xdc\x84\xf8\xc0\x4f\xff\x4e\xcd\x2d\xc0\x91\xa5\xd3\ +\x19\xb3\xe3\x38\x5e\x18\x2a\x7d\x0e\x46\x2e\x24\xbf\x94\x0b\x8a\ +\x0c\x06\x25\x01\xa1\xbd\xd8\x27\x06\x8b\x5f\x05\xe2\xb7\x14\x4d\ +\xea\x1b\x7b\xef\xcd\x88\x0f\xd0\x00\xd0\x88\xef\x5e\x9b\xce\x98\ +\x1c\x85\x38\x08\xbc\x9c\x74\xea\x26\x88\x2e\xf7\xf3\x41\x01\x06\ +\xf5\x21\xab\x7e\x62\x20\xfe\xd4\xac\xe6\x73\x43\x52\x3c\xe3\x7f\ +\x3e\x6a\xd0\x55\x3c\xe7\x18\xb0\x09\x51\x73\xdd\xd0\x00\xd0\x90\ +\xa3\x38\x08\x58\x12\x04\x6d\x23\xd6\x2c\x18\x14\x52\xa4\x6d\x9c\ +\x55\x97\xb1\xf8\x4d\xc5\xd6\x2b\x05\x53\x9f\x7e\x70\xcc\x35\xec\ +\x84\x47\x84\x40\x43\xe6\x46\x83\xe0\x86\x3a\x51\xc2\x93\xfb\xfb\ +\x6d\x7e\x4f\xc6\x10\xbc\x26\x50\x1b\x5f\x30\x96\xe1\xd0\xcb\x53\ +\x31\xbc\x8f\xdf\xf2\xd3\xfe\xd4\xce\x0d\xe7\x6b\x0f\x6f\x7e\xf0\ +\x93\x35\xef\x55\x62\x77\x2b\x31\x38\xef\x80\x41\x53\x30\xf8\x36\ +\x31\x2e\x6d\x0f\x74\x06\xd0\x81\xc2\x3f\x4e\xbf\x8f\x81\x9b\x45\ +\x5e\xe1\x66\x91\xdc\x78\x61\x83\xa9\x92\xf1\x75\x20\x3f\x77\xce\ +\xcf\xac\x2f\x2d\xdb\xb1\xe6\x11\x2c\xbe\x13\x3b\xe1\xbb\x97\x60\ +\xf4\xc3\xaa\x13\x22\x47\x88\xa2\xeb\x46\x1e\x76\x14\x8d\xc0\xca\ +\x4c\xe8\xf7\xbb\x6d\xbb\x51\x27\x3c\x13\xc8\xde\x3b\x00\xa5\xda\ +\x3e\xf0\xd0\xca\xc0\xad\xf6\x27\x65\x38\xcb\xce\x6f\xfb\x70\xfe\ +\xee\x2f\x37\x5e\xc1\x4e\x18\xed\xf0\x2d\xec\x30\xfa\x5b\x48\x0a\ +\x26\x3c\x12\x44\x67\x80\x5b\x01\x2c\xc2\x9e\x7f\xbe\x39\x7d\xb4\ +\xb7\x1c\xde\x4a\x96\x3c\x5a\xa4\x22\xbe\x58\x33\x5e\xfc\x3a\x2c\ +\xfe\x7d\xe9\x4e\x3c\xf2\x57\x3e\x82\xc5\x57\x9a\xf6\x03\xa2\x03\ +\xd7\x23\xbc\x00\x9d\x01\x74\x06\xcf\x04\x03\xbb\x2d\xda\x55\x10\ +\xdb\x6d\x80\xd1\x60\x68\x6b\xbc\x81\x7e\x20\x09\x5c\xe7\x57\xa0\ +\x89\x19\x75\xe7\xaf\x1d\xfc\xdb\xac\xcd\x7f\xfd\x0b\x5c\xea\x81\ +\xd8\xb0\xba\x04\x03\xf1\x85\xbc\x60\x7e\xbc\xb9\xee\x00\xa0\x33\ +\x80\xfe\xd4\x0d\x36\x5f\x5e\x5c\x5f\x7a\x12\x2f\x09\xda\xd2\x27\ +\x28\xfe\x8c\xae\x4d\x57\x47\x26\x5e\x9b\x8f\xc5\x2f\xc5\x4e\x17\ +\xb6\x06\x6c\x8d\xd8\x9a\xb1\x09\xa7\x00\xb0\x1b\x16\x1f\xa0\x33\ +\x80\xce\xe0\x19\x20\x11\xd2\x87\xdf\xf8\xfc\x97\x87\x6b\xac\x2b\ +\x62\x7b\x0c\x64\x61\x26\x10\xc6\x3a\x07\x29\x40\xe2\x72\x54\xa2\ +\xb9\xbd\xdc\xe8\xed\xf9\x77\x47\x93\x1a\x00\x52\x79\x3e\xe0\xbb\ +\x51\xf1\x01\x1a\x00\x1a\x83\x05\x97\xff\xb5\xd4\x80\x38\xf3\x96\ +\x6f\x7f\xfc\x40\x85\x71\x65\x6c\x8f\x41\x38\x08\xc8\xa1\x27\x4f\ +\x04\x41\x23\x78\x4b\x77\x4e\xcf\x16\xb4\xfc\x97\xc3\x61\x85\xaf\ +\x26\x6a\xc0\x7f\x33\xc2\x0b\xd0\x00\xd0\x18\x1c\x00\xf8\x9f\x04\ +\x89\x48\xf3\xdf\xdb\xf5\xc4\x37\x17\xfd\xab\x62\xbb\x0f\xc4\x17\ +\x07\xfc\x19\x18\x1a\x34\xd4\x54\xa2\x59\xdd\x1a\xd1\xb2\x05\xa3\ +\xb8\x9b\x3a\x5a\x88\xdb\x1e\x68\x00\x68\x0c\x88\x47\xb2\x1c\x4a\ +\x42\x3e\xf6\xdf\x7b\x9e\xfc\xe6\xa2\xf7\xcf\xd6\x2e\xfd\x59\x83\ +\xd1\x88\x1a\xaa\x2b\xd0\x83\x5d\x5c\xe8\x9d\x7f\x19\xdd\xe1\x7a\ +\xd0\x00\xf8\x91\x78\xfc\xfd\xbd\x4f\x7d\x73\xc1\xbb\xca\x6b\x4d\ +\x61\x7f\x9e\x55\x8f\x56\x3c\x75\x2f\xd5\x22\xd2\x58\xf8\x61\xde\ +\x53\x4f\x7c\x90\x77\x9a\x14\x29\x14\x0a\x85\x42\xa1\x50\x28\x14\ +\x0a\x85\x42\xa1\x50\x28\x14\x0a\x85\x42\xd1\x1e\x84\xfe\x1f\x55\ +\x0b\x04\x29\x5c\xfb\x2b\x5e\x00\x00\x00\x00\x49\x45\x4e\x44\xae\ +\x42\x60\x82\ " qt_resource_name = b"\ @@ -2559,6 +3677,16 @@ \x07\x03\x7d\xc3\ \x00\x69\ \x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\ +\x00\x12\ +\x0b\xae\x6d\xe7\ +\x00\x73\ +\x00\x74\x00\x65\x00\x72\x00\x65\x00\x6f\x00\x5f\x00\x70\x00\x72\x00\x65\x00\x76\x00\x69\x00\x65\x00\x77\x00\x2e\x00\x70\x00\x6e\ +\x00\x67\ +\x00\x14\ +\x00\xf4\xcc\xc7\ +\x00\x70\ +\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x62\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x6e\x00\x65\x00\x73\x00\x73\x00\x2e\ +\x00\x70\x00\x6e\x00\x67\ \x00\x11\ \x04\xde\x94\x07\ \x00\x70\ @@ -2568,26 +3696,31 @@ \x07\xd7\xe7\xc7\ \x00\x70\ \x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x73\x00\x63\x00\x61\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ -\x00\x12\ -\x03\xa7\x30\x47\ +\x00\x13\ +\x0b\xca\x9e\xc7\ \x00\x70\ -\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x64\x00\x6f\x00\x77\x00\x6e\x00\x6c\x00\x6f\x00\x61\x00\x64\x00\x2e\x00\x70\x00\x6e\ -\x00\x67\ +\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x66\x00\x6f\x00\x72\x00\x62\x00\x69\x00\x64\x00\x64\x00\x65\x00\x6e\x00\x2e\x00\x70\ +\x00\x6e\x00\x67\ +\x00\x19\ +\x0f\x4c\xca\x07\ +\x00\x70\ +\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x64\x00\x69\x00\x67\x00\x69\x00\x74\x00\x61\x00\x6c\x00\x5f\x00\x70\x00\x72\x00\x65\ +\x00\x76\x00\x69\x00\x65\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\ +\x00\x15\ +\x01\xbd\xb5\xe7\ +\x00\x72\ +\x00\x65\x00\x63\x00\x74\x00\x69\x00\x66\x00\x69\x00\x65\x00\x64\x00\x5f\x00\x70\x00\x72\x00\x65\x00\x76\x00\x69\x00\x65\x00\x77\ +\x00\x2e\x00\x70\x00\x6e\x00\x67\ \x00\x15\ \x01\x31\x18\xe7\ \x00\x70\ \x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x63\x00\x65\x00\x72\x00\x74\x00\x69\x00\x66\x00\x69\x00\x63\x00\x61\x00\x74\x00\x65\ \x00\x2e\x00\x70\x00\x6e\x00\x67\ -\x00\x14\ -\x00\xf4\xcc\xc7\ -\x00\x70\ -\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x62\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x6e\x00\x65\x00\x73\x00\x73\x00\x2e\ -\x00\x70\x00\x6e\x00\x67\ -\x00\x13\ -\x0b\xca\x9e\xc7\ +\x00\x12\ +\x03\xa7\x30\x47\ \x00\x70\ -\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x66\x00\x6f\x00\x72\x00\x62\x00\x69\x00\x64\x00\x64\x00\x65\x00\x6e\x00\x2e\x00\x70\ -\x00\x6e\x00\x67\ +\x00\x68\x00\x6f\x00\x74\x00\x6f\x00\x5f\x00\x64\x00\x6f\x00\x77\x00\x6e\x00\x6c\x00\x6f\x00\x61\x00\x64\x00\x2e\x00\x70\x00\x6e\ +\x00\x67\ " qt_resource_struct_v1 = b"\ @@ -2595,13 +3728,16 @@ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x0c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ \x00\x00\x00\x1c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\ -\x00\x00\x00\x56\x00\x02\x00\x00\x00\x06\x00\x00\x00\x05\ -\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x81\x23\ -\x00\x00\x00\xdc\x00\x00\x00\x00\x00\x01\x00\x00\x79\xcd\ -\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x67\x35\ +\x00\x00\x00\x56\x00\x02\x00\x00\x00\x09\x00\x00\x00\x05\ +\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa6\ +\x00\x00\x01\x9e\x00\x00\x00\x00\x00\x01\x00\x00\xc8\xb7\ +\x00\x00\x01\x6e\x00\x00\x00\x00\x00\x01\x00\x00\xa9\x9d\ +\x00\x00\x01\xce\x00\x00\x00\x00\x00\x01\x00\x00\xd0\x0d\ +\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xe0\ +\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x01\x00\x00\x27\x55\ \x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x75\ -\x00\x00\x01\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x86\x5d\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x71\x15\ +\x00\x00\x01\x36\x00\x00\x00\x00\x00\x01\x00\x00\x87\xf3\ " qt_resource_struct_v2 = b"\ @@ -2613,20 +3749,26 @@ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x1c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x56\x00\x02\x00\x00\x00\x06\x00\x00\x00\x05\ +\x00\x00\x00\x56\x00\x02\x00\x00\x00\x09\x00\x00\x00\x05\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x81\x23\ +\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa6\ \x00\x00\x01\x7c\xb6\x3f\x9d\xc6\ -\x00\x00\x00\xdc\x00\x00\x00\x00\x00\x01\x00\x00\x79\xcd\ +\x00\x00\x01\x9e\x00\x00\x00\x00\x00\x01\x00\x00\xc8\xb7\ \x00\x00\x01\x7b\x7c\xa8\xd4\xb4\ -\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x67\x35\ +\x00\x00\x01\x6e\x00\x00\x00\x00\x00\x01\x00\x00\xa9\x9d\ +\x00\x00\x01\x7f\x92\x7b\x65\x66\ +\x00\x00\x01\xce\x00\x00\x00\x00\x00\x01\x00\x00\xd0\x0d\ \x00\x00\x01\x7c\x0d\x03\xa8\x3e\ -\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xe0\ \x00\x00\x01\x7b\x7c\xa8\xd4\xd5\ -\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x75\ +\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x01\x00\x00\x27\x55\ \x00\x00\x01\x7c\x0c\xff\x7e\xca\ -\x00\x00\x01\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x86\x5d\ +\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x7f\x92\x7b\x65\x69\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x71\x15\ \x00\x00\x01\x7c\xc1\x61\xb4\x86\ +\x00\x00\x01\x36\x00\x00\x00\x00\x00\x01\x00\x00\x87\xf3\ +\x00\x00\x01\x7f\xbc\x1f\xde\x32\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/qlib3/photosearchselectiondialog/ui_photosearchselection.ui b/qlib3/photosearchselectiondialog/ui_photosearchselection.ui index 0d7b9ea..56b10ea 100644 --- a/qlib3/photosearchselectiondialog/ui_photosearchselection.ui +++ b/qlib3/photosearchselectiondialog/ui_photosearchselection.ui @@ -6,14 +6,20 @@ 0 0 - 656 - 373 + 400 + 500 + + + 0 + 0 + + - 300 - 300 + 400 + 326 @@ -26,6 +32,18 @@ Photo library search + + + 0 + 0 + + + + + 400 + 300 + + 11 @@ -432,26 +450,70 @@ - - - - 0 - 0 - - - - Preview - - - Preview - - - - 32 - 32 - + + + 1 - + + + + + 0 + 0 + + + + Preview + + + Preview + + + + 32 + 32 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 18 + 16777215 + + + + + 0 + 0 + + + + + + + + 32 + 32 + + + + + @@ -531,6 +593,67 @@ + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + Parallax: +0% + + + + + + + + 0 + 25 + + + + 0 + + + 10 + + + 1 + + + 1 + + + 5 + + + 5 + + + Qt::Horizontal + + + false + + + QSlider::TicksAbove + + + + + + + Inverted stereo + + + + + @@ -762,5 +885,53 @@ + + horizontalSlider_parallax + sliderReleased() + DockWidget + on_parallax_changed() + + + 315 + 651 + + + 345 + 338 + + + + + horizontalSlider_parallax + valueChanged(int) + DockWidget + on_parallax_changed() + + + 315 + 651 + + + 345 + 338 + + + + + checkBox_inverted_stereo + clicked(bool) + DockWidget + on_inverted_stereo(bool) + + + 620 + 650 + + + 345 + 338 + + + diff --git a/resources.qrc b/resources.qrc index 8630a5b..a9a0687 100644 --- a/resources.qrc +++ b/resources.qrc @@ -11,5 +11,6 @@ images/download_all.png images/search.png images/search_coord.png + images/search_name.png diff --git a/resources3/http.py b/resources3/http.py index f877308..31d38a9 100644 --- a/resources3/http.py +++ b/resources3/http.py @@ -1,221 +1,221 @@ -# -*- coding: utf-8 -*- -""" -******************************************************************************* -Module with functions to recover data to make WMS connections to ICGC resources - - ------------------- - begin : 2019-03-27 - author : Albert Adell - email : albert.adell@icgc.cat -******************************************************************************* -""" - -import urllib -import urllib.request -import html -import socket -import re -import os - - -styles_list = [ # (regex_file_pattern, qml_style) - (r".+-caps-municipi-.+", "divisions-administratives-caps-municipi-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - (r".+-municipis-.+", "divisions-administratives-municipis-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - (r".+-comarques-.+", "divisions-administratives-comarques-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - (r".+-vegueries-.+", "divisions-administratives-vegueries-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - (r".+-provincies-.+", "divisions-administratives-provincies-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - (r".+-catalunya-.+", "divisions-administratives-catalunya-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) - ] - -def get_http_dir(url, timeout_seconds=0.5, retries=3): - """ Obté el codi HTML d'una pàgina web amb fitxers - Retorna: string - --- - Gets HTML code of web page with files -        Returns: string - """ - # Llegeixo la pàgina HTTP que informa dels arxius disponibles - remaining_retries = retries - while remaining_retries: - try: - response = None - response = urllib.request.urlopen(url, timeout=timeout_seconds) - remaining_retries = 0 - except socket.timeout: - remaining_retries -= 1 - #print("retries", remaining_retries) - except: - remaining_retries -= 1 - #print("retries", remaining_retries) - if response: - response_data = response.read() - response_data = response_data.decode('utf-8') - else: - response_data = "" - return response_data - -def get_http_files(url, file_regex_pattern, replace_list=[]): - """ Obté una llista de fitxer d'una pàgina web a partir d'una expressió regular - Retorna: llista de resultats de la expressió regular - --- - Gets file list of web page from a regular expression -        Returns: list of regex matches - """ - # LLegeixo les dades HTML del directori HTTP - response_data = get_http_dir(url) - if not response_data: - return [] - # Reemplacem els textos indicats - for search, replace in replace_list: - response_data = response_data.replace(search, replace) - # Obtinc la informació de fitxers a partri de la regex - http_file_regex_pattern = r'' % file_regex_pattern - files_list = re.findall(http_file_regex_pattern, response_data) - return files_list - -def get_dtms(dtm_urlbase_list=[ - ("2m 2008-2011", "https://datacloud.icgc.cat/datacloud/met2_ETRS89/mosaic"), - ("5m 2020", "https://datacloud.icgc.cat/datacloud/met5_ETRS89/mosaic")], - dtm_http_file_pattern=r'(met\w+\.\w+)'): - """ Obté les URLs dels arxius de MET disponibles de l'ICGC - Retorna: [(dtm_name, dtm_url)] - --- - Gets ICGC's available DTM urls -        Returns: [(dtm_name, dtm_url)] - """ - dtm_list = [] - for dtm_name, dtm_urlbase in dtm_urlbase_list: - # Llegeixo la pàgina HTTP que informa dels arxius disponibles - # Cerquem links a arxius MET i ens quedem el més recent - files_list = get_http_files(dtm_urlbase, dtm_http_file_pattern) - if not files_list: - continue - - dtm_file = sorted(files_list, reverse=True)[0] - dtm_url = "%s/%s" % (dtm_urlbase, dtm_file) - dtm_list.append((dtm_name, dtm_url)) - - return dtm_list - -def get_sheets(sheets_urlbase="https://datacloud.icgc.cat/datacloud/talls_ETRS89/json_unzip", - sheet_http_file_pattern=r'(tall(\w+)etrs\w+\.json)'): - """ Obté les URLs dels arxius de talls disponibles de l'ICGC - Retorna: [(sheet_name, sheet_url)] - --- - Gets ICGC's available sheets urls -        Returns: [(sheet_name, sheet_url)] - """ - # Llegeixo la pàgina HTTP que informa dels arxius disponibles - # Cerquem links a arxius json - sheets_info_list = get_http_files(sheets_urlbase, sheet_http_file_pattern) - if not sheets_info_list: - return [] - sheets_info_list.sort(key=lambda sheet_infoi:int(sheet_infoi[1][:-1]) if sheet_infoi[1][:-1].isdigit() and sheet_infoi[1][-1] == "m" else 9999999) - - # Ajustem els noms i generem les urls completes - sheets_list = [] - for sheet_file, sheet_name in sheets_info_list: - if sheet_name[:-1].isdigit() and sheet_name[-1] == 'm': - sheet_name = sheet_name.replace("m", ".000") - sheet_url = "%s/%s" % (sheets_urlbase, sheet_file) - sheets_list.append((sheet_name, sheet_url)) - - return sheets_list - -def get_delimitations_old(delimitations_urlbase="https://datacloud.icgc.cat/datacloud/bm5m_ETRS89/json_unzip/", - delimitation_http_file_pattern=r'(bm5mv\d+js\dt[cp][cmp][\d_]+\.json)', - delimitation_type_patterns_list=[("Caps de Municipi", "bm5mv\d+js\dtcm[\d_]+\.json"), ("Municipis", "bm5mv\d+js\dtpm[\d_]+\.json"), - ("Comarques", "bm5mv\d+js\dtpc[\d_]+\.json"), ("Províncies", "bm5mv\d+js\dtpp[\d_]+\.json")]): - """ Obté les URLs dels arxius de talls disponibles de l'ICGC - Retorna: [(sheet_name, sheet_url)] - --- - Gets ICGC's available sheets urls -        Returns: [(sheet_name, sheet_url)] - """ - # Llegeixo la pàgina HTTP que informa dels arxius disponibles - delimitations_info_list = get_http_files(delimitations_urlbase, delimitation_http_file_pattern) - - # Cerquem links a arxius json - delimitations_list = [] - for delimitation_name, delimitation_type_pattern in delimitation_type_patterns_list: - for delimitation_file in delimitations_info_list: - # Cerquem el fitxer que quadri amb cada plantilla de tipus - if re.match(delimitation_type_pattern, delimitation_file): - delimitation_url = "%s/%s" % (delimitations_urlbase, delimitation_file) - delimitations_list.append((delimitation_name, delimitation_url)) - break - - return delimitations_list - -def get_delimitations(delimitations_urlbase="https://datacloud.icgc.cat/datacloud/divisions-administratives/json_unzip/", - delimitation_http_file_pattern=r'(divisions-administratives-v\d+r\d+\-(\D+)(?:-(\d+))*-(\d{8})\.json)'): - """ Obté les URLs dels arxius de talls disponibles de l'ICGC - Retorna: [(sheet_name, sheet_url)] - --- - Gets ICGC's available sheets urls -        Returns: [(sheet_name, sheet_url)] - """ - # Llegeixo la pàgina HTTP que informa dels arxius disponibles (canvio "caps-municipi" per parsejar-lo més fàcil...) - delimitations_info_list = get_http_files(delimitations_urlbase, delimitation_http_file_pattern) - delimitations_info_list.sort(key=lambda d:d[0], reverse=True) - # Cerquem links a arxius json (només ens quedem els de la data més nova) - delimitations_dict = {} - last_name = None - last_scale = None - for filename, name, scale, date in delimitations_info_list: - # Ens quedem el primer (el de data més nova -> sort reverse) - if last_name != name or last_scale != scale: - delimitations_dict[name] = delimitations_dict.get(name, []) + [(int(scale) if scale else None, "%s/%s" % (delimitations_urlbase, filename))] - last_name = name - last_scale = scale - - # Ordenem els arxius... - order_dict = { - "caps-municipi": 1, - "municipis": 2, - "comarques": 3, - "vegueries": 4, - "provincies": 5, - "catalunya": 6 - } - #delimitations_list = sorted(list(delimitations_dict.items()), key=lambda d: order_dict.get(d[0], 0) * 1000000 + d[1][0]) # index(name) * 1000000 + scale - delimitations_list = sorted(list(delimitations_dict.items()), key=lambda d: order_dict[d[0]]) - delimitations_list = [(name, sorted(scale_list, key=lambda s: s[0])) for name, scale_list in delimitations_list] - return delimitations_list - -def get_ndvis(urlbase="https://datacloud.icgc.cat/datacloud/ndvi/tif/", - http_file_pattern=r'(ndvi-v\d+r\d+-(\d+)\.tif)'): - """ Obté les URLs dels arxius NDVI disponibles de l'ICGC - Retorna: [(year, ndvi_url)] - --- - Gets ICGC's available NDVI file urls -        Returns: [(year, ndvi_url)] - """ - # Llegeixo la pàgina HTTP que informa dels arxius disponibles - # Cerquem links a arxius json - info_list = get_http_files(urlbase, http_file_pattern) - file_tuple_list = [(year, "%s/%s" % (urlbase, filename)) for filename, year in info_list] - file_tuple_list.sort(key=lambda f : f[0]) # Ordenem per any - return file_tuple_list - -def get_topographic_5k(urlbase="https://datacloud.icgc.cat/datacloud/topografia-territorial/tif_unzip", - http_file_pattern=r'(topografia-territorial-v\d+r\d+-(\d+)\.tif)'): - """ Obté les URLs dels arxius de topografia 1:5.000 disponibles de l'ICGC - Retorna: [(year, ndvi_url)] - --- - Gets ICGC's available topography 1:5,000 file urls -        Returns: [(year, ndvi_url)] - """ - info_list = get_http_files(urlbase, http_file_pattern) - file_tuple_list = [(year, "%s/%s" % (urlbase, filename)) for filename, year in info_list] - file_tuple_list.sort(key=lambda f : f[0]) # Ordenem per any - return file_tuple_list - -def get_regex_styles(): - """ Retorna la llista d'estils disponibles amb el path al seu QML """ - final_styles_list = [ - (style_regex, - # Injectem el path dels arxiu .qml - os.path.join(os.path.dirname(__file__), "symbols", style_qml) if style_qml else None - ) for style_regex, style_qml in styles_list] - return final_styles_list +# -*- coding: utf-8 -*- +""" +******************************************************************************* +Module with functions to recover data to make WMS connections to ICGC resources + + ------------------- + begin : 2019-03-27 + author : Albert Adell + email : albert.adell@icgc.cat +******************************************************************************* +""" + +import urllib +import urllib.request +import html +import socket +import re +import os + + +styles_list = [ # (regex_file_pattern, qml_style) + (r".+-caps-municipi-.+", "divisions-administratives-caps-municipi-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + (r".+-municipis-.+", "divisions-administratives-municipis-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + (r".+-comarques-.+", "divisions-administratives-comarques-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + (r".+-vegueries-.+", "divisions-administratives-vegueries-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + (r".+-provincies-.+", "divisions-administratives-provincies-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + (r".+-catalunya-.+", "divisions-administratives-catalunya-ref.qml"), # ct1mv22sh0f4483707eaxt1 (Textos) + ] + +def get_http_dir(url, timeout_seconds=0.5, retries=3): + """ Obté el codi HTML d'una pàgina web amb fitxers + Retorna: string + --- + Gets HTML code of web page with files +        Returns: string + """ + # Llegeixo la pàgina HTTP que informa dels arxius disponibles + remaining_retries = retries + while remaining_retries: + try: + response = None + response = urllib.request.urlopen(url, timeout=timeout_seconds) + remaining_retries = 0 + except socket.timeout: + remaining_retries -= 1 + #print("retries", remaining_retries) + except: + remaining_retries -= 1 + #print("retries", remaining_retries) + if response: + response_data = response.read() + response_data = response_data.decode('utf-8') + else: + response_data = "" + return response_data + +def get_http_files(url, file_regex_pattern, replace_list=[]): + """ Obté una llista de fitxer d'una pàgina web a partir d'una expressió regular + Retorna: llista de resultats de la expressió regular + --- + Gets file list of web page from a regular expression +        Returns: list of regex matches + """ + # LLegeixo les dades HTML del directori HTTP + response_data = get_http_dir(url) + if not response_data: + return [] + # Reemplacem els textos indicats + for search, replace in replace_list: + response_data = response_data.replace(search, replace) + # Obtinc la informació de fitxers a partri de la regex + http_file_regex_pattern = r'' % file_regex_pattern + files_list = re.findall(http_file_regex_pattern, response_data) + return files_list + +def get_dtms(dtm_urlbase_list=[ + ("2m 2008-2011", "https://datacloud.icgc.cat/datacloud/met2_ETRS89/mosaic"), + ("5m 2020", "https://datacloud.icgc.cat/datacloud/met5_ETRS89/mosaic")], + dtm_http_file_pattern=r'(met\w+\.\w+)'): + """ Obté les URLs dels arxius de MET disponibles de l'ICGC + Retorna: [(dtm_name, dtm_url)] + --- + Gets ICGC's available DTM urls +        Returns: [(dtm_name, dtm_url)] + """ + dtm_list = [] + for dtm_name, dtm_urlbase in dtm_urlbase_list: + # Llegeixo la pàgina HTTP que informa dels arxius disponibles + # Cerquem links a arxius MET i ens quedem el més recent + files_list = get_http_files(dtm_urlbase, dtm_http_file_pattern) + if not files_list: + continue + + dtm_file = sorted(files_list, reverse=True)[0] + dtm_url = "%s/%s" % (dtm_urlbase, dtm_file) + dtm_list.append((dtm_name, dtm_url)) + + return dtm_list + +def get_sheets(sheets_urlbase="https://datacloud.icgc.cat/datacloud/talls_ETRS89/json_unzip", + sheet_http_file_pattern=r'(tall(\w+)etrs\w+\.json)'): + """ Obté les URLs dels arxius de talls disponibles de l'ICGC + Retorna: [(sheet_name, sheet_url)] + --- + Gets ICGC's available sheets urls +        Returns: [(sheet_name, sheet_url)] + """ + # Llegeixo la pàgina HTTP que informa dels arxius disponibles + # Cerquem links a arxius json + sheets_info_list = get_http_files(sheets_urlbase, sheet_http_file_pattern) + if not sheets_info_list: + return [] + sheets_info_list.sort(key=lambda sheet_infoi:int(sheet_infoi[1][:-1]) if sheet_infoi[1][:-1].isdigit() and sheet_infoi[1][-1] == "m" else 9999999) + + # Ajustem els noms i generem les urls completes + sheets_list = [] + for sheet_file, sheet_name in sheets_info_list: + if sheet_name[:-1].isdigit() and sheet_name[-1] == 'm': + sheet_name = sheet_name.replace("m", ".000") + sheet_url = "%s/%s" % (sheets_urlbase, sheet_file) + sheets_list.append((sheet_name, sheet_url)) + + return sheets_list + +def get_delimitations_old(delimitations_urlbase="https://datacloud.icgc.cat/datacloud/bm5m_ETRS89/json_unzip/", + delimitation_http_file_pattern=r'(bm5mv\d+js\dt[cp][cmp][\d_]+\.json)', + delimitation_type_patterns_list=[("Caps de Municipi", "bm5mv\d+js\dtcm[\d_]+\.json"), ("Municipis", "bm5mv\d+js\dtpm[\d_]+\.json"), + ("Comarques", "bm5mv\d+js\dtpc[\d_]+\.json"), ("Províncies", "bm5mv\d+js\dtpp[\d_]+\.json")]): + """ Obté les URLs dels arxius de talls disponibles de l'ICGC + Retorna: [(sheet_name, sheet_url)] + --- + Gets ICGC's available sheets urls +        Returns: [(sheet_name, sheet_url)] + """ + # Llegeixo la pàgina HTTP que informa dels arxius disponibles + delimitations_info_list = get_http_files(delimitations_urlbase, delimitation_http_file_pattern) + + # Cerquem links a arxius json + delimitations_list = [] + for delimitation_name, delimitation_type_pattern in delimitation_type_patterns_list: + for delimitation_file in delimitations_info_list: + # Cerquem el fitxer que quadri amb cada plantilla de tipus + if re.match(delimitation_type_pattern, delimitation_file): + delimitation_url = "%s/%s" % (delimitations_urlbase, delimitation_file) + delimitations_list.append((delimitation_name, delimitation_url)) + break + + return delimitations_list + +def get_delimitations(delimitations_urlbase="https://datacloud.icgc.cat/datacloud/divisions-administratives/json_unzip/", + delimitation_http_file_pattern=r'(divisions-administratives-v\d+r\d+\-(\D+)(?:-(\d+))*-(\d{8})\.json)'): + """ Obté les URLs dels arxius de talls disponibles de l'ICGC + Retorna: [(sheet_name, sheet_url)] + --- + Gets ICGC's available sheets urls +        Returns: [(sheet_name, sheet_url)] + """ + # Llegeixo la pàgina HTTP que informa dels arxius disponibles (canvio "caps-municipi" per parsejar-lo més fàcil...) + delimitations_info_list = get_http_files(delimitations_urlbase, delimitation_http_file_pattern) + delimitations_info_list.sort(key=lambda d:d[0], reverse=True) + # Cerquem links a arxius json (només ens quedem els de la data més nova) + delimitations_dict = {} + last_name = None + last_scale = None + for filename, name, scale, date in delimitations_info_list: + # Ens quedem el primer (el de data més nova -> sort reverse) + if last_name != name or last_scale != scale: + delimitations_dict[name] = delimitations_dict.get(name, []) + [(int(scale) if scale else None, "%s/%s" % (delimitations_urlbase, filename))] + last_name = name + last_scale = scale + + # Ordenem els arxius... + order_dict = { + "caps-municipi": 1, + "municipis": 2, + "comarques": 3, + "vegueries": 4, + "provincies": 5, + "catalunya": 6 + } + #delimitations_list = sorted(list(delimitations_dict.items()), key=lambda d: order_dict.get(d[0], 0) * 1000000 + d[1][0]) # index(name) * 1000000 + scale + delimitations_list = sorted(list(delimitations_dict.items()), key=lambda d: order_dict[d[0]]) + delimitations_list = [(name, sorted(scale_list, key=lambda s: s[0])) for name, scale_list in delimitations_list] + return delimitations_list + +def get_ndvis(urlbase="https://datacloud.icgc.cat/datacloud/ndvi/tif/", + http_file_pattern=r'(ndvi-v\d+r\d+-(\d+)\.tif)'): + """ Obté les URLs dels arxius NDVI disponibles de l'ICGC + Retorna: [(year, ndvi_url)] + --- + Gets ICGC's available NDVI file urls +        Returns: [(year, ndvi_url)] + """ + # Llegeixo la pàgina HTTP que informa dels arxius disponibles + # Cerquem links a arxius json + info_list = get_http_files(urlbase, http_file_pattern) + file_tuple_list = [(year, "%s/%s" % (urlbase, filename)) for filename, year in info_list] + file_tuple_list.sort(key=lambda f : f[0]) # Ordenem per any + return file_tuple_list + +def get_topographic_5k(urlbase="https://datacloud.icgc.cat/datacloud/topografia-territorial/tif_unzip", + http_file_pattern=r'(topografia-territorial-v\d+r\d+-(\d+)\.tif)'): + """ Obté les URLs dels arxius de topografia 1:5.000 disponibles de l'ICGC + Retorna: [(year, ndvi_url)] + --- + Gets ICGC's available topography 1:5,000 file urls +        Returns: [(year, ndvi_url)] + """ + info_list = get_http_files(urlbase, http_file_pattern) + file_tuple_list = [(year, "%s/%s" % (urlbase, filename)) for filename, year in info_list] + file_tuple_list.sort(key=lambda f : f[0]) # Ordenem per any + return file_tuple_list + +def get_regex_styles(): + """ Retorna la llista d'estils disponibles amb el path al seu QML """ + final_styles_list = [ + (style_regex, + # Injectem el path dels arxiu .qml + os.path.join(os.path.dirname(__file__), "symbols", style_qml) if style_qml else None + ) for style_regex, style_qml in styles_list] + return final_styles_list