[DebianGIS-dev] r718 - in packages/thuban: . branches
branches/upstream branches/upstream/current
branches/upstream/current/Doc branches/upstream/current/Doc/manual
branches/upstream/current/Doc/manual/images
branches/upstream/current/Doc/technotes
branches/upstream/current/Examples
branches/upstream/current/Examples/simple_extensions
branches/upstream/current/Extensions
branches/upstream/current/Extensions/bboxdump
branches/upstream/current/Extensions/drawshape
branches/upstream/current/Extensions/export_shapefile
branches/upstream/current/Extensions/gns2shp
branches/upstream/current/Extensions/gns2shp/test
branches/upstream/current/Extensions/importAPR
branches/upstream/current/Extensions/importAPR/samples
branches/upstream/current/Extensions/importAPR/test
branches/upstream/current/Extensions/mouseposition
branches/upstream/current/Extensions/ogr
branches/upstream/current/Extensions/ogr/test
branches/upstream/current/Extensions/profiling
branches/upstream/current/Extensions/svgexport
branches/upstream/current/Extensions/svgexport/test
branches/upstream/current/Extensions/umn_mapserver
branches/upstream/current/Extensions/umn_mapserver/sample
branches/upstream/current/Extensions/umn_mapserver/test
branches/upstream/current/Extensions/wms
branches/upstream/current/Extensions/wms/test
branches/upstream/current/Resources
branches/upstream/current/Resources/Bitmaps
branches/upstream/current/Resources/Locale
branches/upstream/current/Resources/Locale/de
branches/upstream/current/Resources/Locale/de/LC_MESSAGES
branches/upstream/current/Resources/Locale/es
branches/upstream/current/Resources/Locale/es/LC_MESSAGES
branches/upstream/current/Resources/Locale/fr
branches/upstream/current/Resources/Locale/fr/LC_MESSAGES
branches/upstream/current/Resources/Locale/hu
branches/upstream/current/Resources/Locale/hu/LC_MESSAGES
branches/upstream/current/Resources/Locale/it
branches/upstream/current/Resources/Locale/it/LC_MESSAGES
branches/upstream/current/Resources/Locale/pt_BR
branches/upstream/current/Resources/Locale/pt_BR/LC_MESSAGES
branches/upstream/current/Resources/Locale/ru
branches/upstream/current/Resources/Locale/ru/LC_MESSAGES
branches/upstream/current/Resources/Projections
branches/upstream/current/Resources/XML
branches/upstream/current/Thuban
branches/upstream/current/Thuban/Lib
branches/upstream/current/Thuban/Model
branches/upstream/current/Thuban/UI
branches/upstream/current/devtools
branches/upstream/current/libraries
branches/upstream/current/libraries/pyprojection
branches/upstream/current/libraries/pyshapelib
branches/upstream/current/libraries/shapelib
branches/upstream/current/libraries/thuban
branches/upstream/current/po branches/upstream/current/test
Francesco Lovergine
frankie at alioth.debian.org
Fri Apr 6 11:44:57 UTC 2007
Author: frankie
Date: 2007-04-06 11:44:54 +0000 (Fri, 06 Apr 2007)
New Revision: 718
Added:
packages/thuban/branches/
packages/thuban/branches/upstream/
packages/thuban/branches/upstream/current/
packages/thuban/branches/upstream/current/COPYING
packages/thuban/branches/upstream/current/ChangeLog
packages/thuban/branches/upstream/current/Doc/
packages/thuban/branches/upstream/current/Doc/README
packages/thuban/branches/upstream/current/Doc/ThubanModel.org.xmi
packages/thuban/branches/upstream/current/Doc/ThubanModel.xmi
packages/thuban/branches/upstream/current/Doc/manual/
packages/thuban/branches/upstream/current/Doc/manual/Makefile
packages/thuban/branches/upstream/current/Doc/manual/README
packages/thuban/branches/upstream/current/Doc/manual/images/
packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_close.png
packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_dock.png
packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.png
packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.ps
packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.sk
packages/thuban/branches/upstream/current/Doc/manual/images/2_4_session_tree.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullextent.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fulllayerextent.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullshapeextent.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_pan.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomin.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomout.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_3_identify.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_3_label.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_invisible.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_legend.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_movedown.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_moveup.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_popup_menu.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_props.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_tobottom.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_totop.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_5_visible.png
packages/thuban/branches/upstream/current/Doc/manual/images/3_rename_map.png
packages/thuban/branches/upstream/current/Doc/manual/images/4_2_layer_properties.png
packages/thuban/branches/upstream/current/Doc/manual/images/4_2_raster_layer_properties.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_2_custom_ramp.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_2_quantiles.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_2_uniform_dist.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_2_unique_values.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_3_genclass.png
packages/thuban/branches/upstream/current/Doc/manual/images/5_classification.png
packages/thuban/branches/upstream/current/Doc/manual/images/6_projection.png
packages/thuban/branches/upstream/current/Doc/manual/images/7_1_table_view.png
packages/thuban/branches/upstream/current/Doc/manual/images/7_2_5_join.png
packages/thuban/branches/upstream/current/Doc/manual/images/8_int_error.png
packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_add_layer.png
packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_add.png
packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_management.png
packages/thuban/branches/upstream/current/Doc/manual/mainwindow.png
packages/thuban/branches/upstream/current/Doc/manual/mainwindow.xcf
packages/thuban/branches/upstream/current/Doc/manual/thuban-manual-de.xml
packages/thuban/branches/upstream/current/Doc/manual/thuban-manual.xml
packages/thuban/branches/upstream/current/Doc/technotes/
packages/thuban/branches/upstream/current/Doc/technotes/README
packages/thuban/branches/upstream/current/Doc/technotes/coding_guidelines.txt
packages/thuban/branches/upstream/current/Doc/technotes/release_process.txt
packages/thuban/branches/upstream/current/Doc/technotes/string_representation.txt
packages/thuban/branches/upstream/current/Examples/
packages/thuban/branches/upstream/current/Examples/__init__.py
packages/thuban/branches/upstream/current/Examples/simple_extensions/
packages/thuban/branches/upstream/current/Examples/simple_extensions/README
packages/thuban/branches/upstream/current/Examples/simple_extensions/__init__.py
packages/thuban/branches/upstream/current/Examples/simple_extensions/hello_world.py
packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_command.py
packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.py
packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.xpm
packages/thuban/branches/upstream/current/Extensions/
packages/thuban/branches/upstream/current/Extensions/__init__.py
packages/thuban/branches/upstream/current/Extensions/bboxdump/
packages/thuban/branches/upstream/current/Extensions/bboxdump/__init__.py
packages/thuban/branches/upstream/current/Extensions/bboxdump/bboxdump.py
packages/thuban/branches/upstream/current/Extensions/drawshape/
packages/thuban/branches/upstream/current/Extensions/drawshape/README
packages/thuban/branches/upstream/current/Extensions/drawshape/drawshape.py
packages/thuban/branches/upstream/current/Extensions/drawshape/patch.diff
packages/thuban/branches/upstream/current/Extensions/export_shapefile/
packages/thuban/branches/upstream/current/Extensions/export_shapefile/__init__.py
packages/thuban/branches/upstream/current/Extensions/export_shapefile/export_shapefile.py
packages/thuban/branches/upstream/current/Extensions/gns2shp/
packages/thuban/branches/upstream/current/Extensions/gns2shp/__init__.py
packages/thuban/branches/upstream/current/Extensions/gns2shp/gns2shp.py
packages/thuban/branches/upstream/current/Extensions/gns2shp/test/
packages/thuban/branches/upstream/current/Extensions/gns2shp/test/README
packages/thuban/branches/upstream/current/Extensions/gns2shp/test/__init__.py
packages/thuban/branches/upstream/current/Extensions/gns2shp/test/ls.txt
packages/thuban/branches/upstream/current/Extensions/gns2shp/test/test_gns2shp.py
packages/thuban/branches/upstream/current/Extensions/importAPR/
packages/thuban/branches/upstream/current/Extensions/importAPR/__init__.py
packages/thuban/branches/upstream/current/Extensions/importAPR/apr.py
packages/thuban/branches/upstream/current/Extensions/importAPR/importAPR.py
packages/thuban/branches/upstream/current/Extensions/importAPR/odb.py
packages/thuban/branches/upstream/current/Extensions/importAPR/samples/
packages/thuban/branches/upstream/current/Extensions/importAPR/samples/README
packages/thuban/branches/upstream/current/Extensions/importAPR/samples/iceland.apr
packages/thuban/branches/upstream/current/Extensions/importAPR/test/
packages/thuban/branches/upstream/current/Extensions/importAPR/test/README
packages/thuban/branches/upstream/current/Extensions/importAPR/test/test_apr.py
packages/thuban/branches/upstream/current/Extensions/mouseposition/
packages/thuban/branches/upstream/current/Extensions/mouseposition/__init__.py
packages/thuban/branches/upstream/current/Extensions/mouseposition/mouseposition.py
packages/thuban/branches/upstream/current/Extensions/mouseposition/position.xpm
packages/thuban/branches/upstream/current/Extensions/ogr/
packages/thuban/branches/upstream/current/Extensions/ogr/__init__.py
packages/thuban/branches/upstream/current/Extensions/ogr/ogrdialog.py
packages/thuban/branches/upstream/current/Extensions/ogr/ogrshapes.py
packages/thuban/branches/upstream/current/Extensions/ogr/ogrstart.py
packages/thuban/branches/upstream/current/Extensions/ogr/test/
packages/thuban/branches/upstream/current/Extensions/ogr/test/__init__.py
packages/thuban/branches/upstream/current/Extensions/ogr/test/test_OGRShapestore.py
packages/thuban/branches/upstream/current/Extensions/ogr/x.diff
packages/thuban/branches/upstream/current/Extensions/profiling/
packages/thuban/branches/upstream/current/Extensions/profiling/__init__.py
packages/thuban/branches/upstream/current/Extensions/profiling/profiling.py
packages/thuban/branches/upstream/current/Extensions/svgexport/
packages/thuban/branches/upstream/current/Extensions/svgexport/__init__.py
packages/thuban/branches/upstream/current/Extensions/svgexport/maplegend.py
packages/thuban/branches/upstream/current/Extensions/svgexport/svgmapwriter.py
packages/thuban/branches/upstream/current/Extensions/svgexport/svgsaver.py
packages/thuban/branches/upstream/current/Extensions/svgexport/test/
packages/thuban/branches/upstream/current/Extensions/svgexport/test/__init__.py
packages/thuban/branches/upstream/current/Extensions/svgexport/test/test_svgmapwriter.py
packages/thuban/branches/upstream/current/Extensions/svgexport/x.diff
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/README
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/__init__.py
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mapfile.py
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_export.py
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_handle.py
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_import.py
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/sample/
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/sample/README
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/README
packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/test_mapserver.py
packages/thuban/branches/upstream/current/Extensions/wms/
packages/thuban/branches/upstream/current/Extensions/wms/__init__.py
packages/thuban/branches/upstream/current/Extensions/wms/capabilities.py
packages/thuban/branches/upstream/current/Extensions/wms/domutils.py
packages/thuban/branches/upstream/current/Extensions/wms/infodialog.py
packages/thuban/branches/upstream/current/Extensions/wms/layer.py
packages/thuban/branches/upstream/current/Extensions/wms/parser.py
packages/thuban/branches/upstream/current/Extensions/wms/properties.py
packages/thuban/branches/upstream/current/Extensions/wms/test/
packages/thuban/branches/upstream/current/Extensions/wms/test/adjustpath.py
packages/thuban/branches/upstream/current/Extensions/wms/test/test_domutils.py
packages/thuban/branches/upstream/current/Extensions/wms/test/test_ogclib.py
packages/thuban/branches/upstream/current/Extensions/wms/test/test_parser.py
packages/thuban/branches/upstream/current/Extensions/wms/wms.py
packages/thuban/branches/upstream/current/MANIFEST.in
packages/thuban/branches/upstream/current/NEWS
packages/thuban/branches/upstream/current/PKG-INFO
packages/thuban/branches/upstream/current/README
packages/thuban/branches/upstream/current/Resources/
packages/thuban/branches/upstream/current/Resources/Bitmaps/
packages/thuban/branches/upstream/current/Resources/Bitmaps/bottom_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/close_12.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/dock_12.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/fullextent.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/fulllayerextent.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/fullselextent.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_all.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_none.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_not.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/hide_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/identify.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/label.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/layer_properties.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_map.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/lower_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/pan.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/raise_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/show_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/top_layer.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/undock_12.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_in.xpm
packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_out.xpm
packages/thuban/branches/upstream/current/Resources/Locale/
packages/thuban/branches/upstream/current/Resources/Locale/de/
packages/thuban/branches/upstream/current/Resources/Locale/de/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/de/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/es/
packages/thuban/branches/upstream/current/Resources/Locale/es/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/es/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/fr/
packages/thuban/branches/upstream/current/Resources/Locale/fr/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/fr/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/hu/
packages/thuban/branches/upstream/current/Resources/Locale/hu/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/hu/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/it/
packages/thuban/branches/upstream/current/Resources/Locale/it/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/it/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/pt_BR/
packages/thuban/branches/upstream/current/Resources/Locale/pt_BR/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/pt_BR/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Locale/ru/
packages/thuban/branches/upstream/current/Resources/Locale/ru/LC_MESSAGES/
packages/thuban/branches/upstream/current/Resources/Locale/ru/LC_MESSAGES/thuban.mo
packages/thuban/branches/upstream/current/Resources/Projections/
packages/thuban/branches/upstream/current/Resources/Projections/defaults.proj
packages/thuban/branches/upstream/current/Resources/Projections/epsg-deprecated.proj
packages/thuban/branches/upstream/current/Resources/Projections/epsg.proj
packages/thuban/branches/upstream/current/Resources/XML/
packages/thuban/branches/upstream/current/Resources/XML/projfile.dtd
packages/thuban/branches/upstream/current/Resources/XML/thuban-0.8.dtd
packages/thuban/branches/upstream/current/Resources/XML/thuban-0.9.dtd
packages/thuban/branches/upstream/current/Resources/XML/thuban-1.0.dtd
packages/thuban/branches/upstream/current/Resources/XML/thuban-1.1.dtd
packages/thuban/branches/upstream/current/Resources/XML/thuban.dtd
packages/thuban/branches/upstream/current/Thuban/
packages/thuban/branches/upstream/current/Thuban/Lib/
packages/thuban/branches/upstream/current/Thuban/Lib/__init__.py
packages/thuban/branches/upstream/current/Thuban/Lib/classmapper.py
packages/thuban/branches/upstream/current/Thuban/Lib/connector.py
packages/thuban/branches/upstream/current/Thuban/Lib/fileutil.py
packages/thuban/branches/upstream/current/Thuban/Lib/version.py
packages/thuban/branches/upstream/current/Thuban/Model/
packages/thuban/branches/upstream/current/Thuban/Model/__init__.py
packages/thuban/branches/upstream/current/Thuban/Model/base.py
packages/thuban/branches/upstream/current/Thuban/Model/classgen.py
packages/thuban/branches/upstream/current/Thuban/Model/classification.py
packages/thuban/branches/upstream/current/Thuban/Model/color.py
packages/thuban/branches/upstream/current/Thuban/Model/data.py
packages/thuban/branches/upstream/current/Thuban/Model/extension.py
packages/thuban/branches/upstream/current/Thuban/Model/label.py
packages/thuban/branches/upstream/current/Thuban/Model/layer.py
packages/thuban/branches/upstream/current/Thuban/Model/load.py
packages/thuban/branches/upstream/current/Thuban/Model/map.py
packages/thuban/branches/upstream/current/Thuban/Model/messages.py
packages/thuban/branches/upstream/current/Thuban/Model/postgisdb.py
packages/thuban/branches/upstream/current/Thuban/Model/proj.py
packages/thuban/branches/upstream/current/Thuban/Model/range.py
packages/thuban/branches/upstream/current/Thuban/Model/resource.py
packages/thuban/branches/upstream/current/Thuban/Model/save.py
packages/thuban/branches/upstream/current/Thuban/Model/scalebar.py
packages/thuban/branches/upstream/current/Thuban/Model/session.py
packages/thuban/branches/upstream/current/Thuban/Model/table.py
packages/thuban/branches/upstream/current/Thuban/Model/transientdb.py
packages/thuban/branches/upstream/current/Thuban/Model/wellknowntext.py
packages/thuban/branches/upstream/current/Thuban/Model/xmlreader.py
packages/thuban/branches/upstream/current/Thuban/Model/xmlwriter.py
packages/thuban/branches/upstream/current/Thuban/UI/
packages/thuban/branches/upstream/current/Thuban/UI/__init__.py
packages/thuban/branches/upstream/current/Thuban/UI/about.py
packages/thuban/branches/upstream/current/Thuban/UI/altpathdialog.py
packages/thuban/branches/upstream/current/Thuban/UI/application.py
packages/thuban/branches/upstream/current/Thuban/UI/baserenderer.py
packages/thuban/branches/upstream/current/Thuban/UI/classgen.py
packages/thuban/branches/upstream/current/Thuban/UI/classifier.py
packages/thuban/branches/upstream/current/Thuban/UI/colordialog.py
packages/thuban/branches/upstream/current/Thuban/UI/command.py
packages/thuban/branches/upstream/current/Thuban/UI/common.py
packages/thuban/branches/upstream/current/Thuban/UI/context.py
packages/thuban/branches/upstream/current/Thuban/UI/controls.py
packages/thuban/branches/upstream/current/Thuban/UI/dbdialog.py
packages/thuban/branches/upstream/current/Thuban/UI/dialogs.py
packages/thuban/branches/upstream/current/Thuban/UI/dock.py
packages/thuban/branches/upstream/current/Thuban/UI/exceptiondialog.py
packages/thuban/branches/upstream/current/Thuban/UI/extensionregistry.py
packages/thuban/branches/upstream/current/Thuban/UI/hittest.py
packages/thuban/branches/upstream/current/Thuban/UI/identifyview.py
packages/thuban/branches/upstream/current/Thuban/UI/join.py
packages/thuban/branches/upstream/current/Thuban/UI/labeldialog.py
packages/thuban/branches/upstream/current/Thuban/UI/layerproperties.py
packages/thuban/branches/upstream/current/Thuban/UI/legend.py
packages/thuban/branches/upstream/current/Thuban/UI/main.py
packages/thuban/branches/upstream/current/Thuban/UI/mainwindow.py
packages/thuban/branches/upstream/current/Thuban/UI/menu.py
packages/thuban/branches/upstream/current/Thuban/UI/messages.py
packages/thuban/branches/upstream/current/Thuban/UI/multiplechoicedialog.py
packages/thuban/branches/upstream/current/Thuban/UI/projdialog.py
packages/thuban/branches/upstream/current/Thuban/UI/projlist.py
packages/thuban/branches/upstream/current/Thuban/UI/rasterlayerproperties.py
packages/thuban/branches/upstream/current/Thuban/UI/renderer.py
packages/thuban/branches/upstream/current/Thuban/UI/resource.py
packages/thuban/branches/upstream/current/Thuban/UI/scalebar.py
packages/thuban/branches/upstream/current/Thuban/UI/selection.py
packages/thuban/branches/upstream/current/Thuban/UI/sizers.py
packages/thuban/branches/upstream/current/Thuban/UI/tableview.py
packages/thuban/branches/upstream/current/Thuban/UI/tree.py
packages/thuban/branches/upstream/current/Thuban/UI/view.py
packages/thuban/branches/upstream/current/Thuban/UI/viewport.py
packages/thuban/branches/upstream/current/Thuban/__init__.py
packages/thuban/branches/upstream/current/Thuban/version.py
packages/thuban/branches/upstream/current/devtools/
packages/thuban/branches/upstream/current/devtools/create_epsg.py
packages/thuban/branches/upstream/current/libraries/
packages/thuban/branches/upstream/current/libraries/pyprojection/
packages/thuban/branches/upstream/current/libraries/pyprojection/LICENSE
packages/thuban/branches/upstream/current/libraries/pyprojection/MANIFEST.in
packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.i
packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.py
packages/thuban/branches/upstream/current/libraries/pyprojection/Projection_wrap.c
packages/thuban/branches/upstream/current/libraries/pyprojection/setup.py
packages/thuban/branches/upstream/current/libraries/pyprojection/swighelp.txt
packages/thuban/branches/upstream/current/libraries/pyshapelib/
packages/thuban/branches/upstream/current/libraries/pyshapelib/COPYING
packages/thuban/branches/upstream/current/libraries/pyshapelib/ChangeLog
packages/thuban/branches/upstream/current/libraries/pyshapelib/MANIFEST.in
packages/thuban/branches/upstream/current/libraries/pyshapelib/NEWS
packages/thuban/branches/upstream/current/libraries/pyshapelib/README
packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.i
packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.py
packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib_wrap.c
packages/thuban/branches/upstream/current/libraries/pyshapelib/pyshapelib_api.h
packages/thuban/branches/upstream/current/libraries/pyshapelib/pytest.py
packages/thuban/branches/upstream/current/libraries/pyshapelib/setup.py
packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.i
packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.py
packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib_wrap.c
packages/thuban/branches/upstream/current/libraries/pyshapelib/shptreemodule.c
packages/thuban/branches/upstream/current/libraries/pyshapelib/testdbf.py
packages/thuban/branches/upstream/current/libraries/shapelib/
packages/thuban/branches/upstream/current/libraries/shapelib/dbfopen.c
packages/thuban/branches/upstream/current/libraries/shapelib/shapefil.h
packages/thuban/branches/upstream/current/libraries/shapelib/shpopen.c
packages/thuban/branches/upstream/current/libraries/shapelib/shptree.c
packages/thuban/branches/upstream/current/libraries/thuban/
packages/thuban/branches/upstream/current/libraries/thuban/gdalwarp.cpp
packages/thuban/branches/upstream/current/libraries/thuban/swigPtrConvertHack.h
packages/thuban/branches/upstream/current/libraries/thuban/wxPython_int.h
packages/thuban/branches/upstream/current/libraries/thuban/wxproj.cpp
packages/thuban/branches/upstream/current/po/
packages/thuban/branches/upstream/current/po/Makefile
packages/thuban/branches/upstream/current/po/README
packages/thuban/branches/upstream/current/po/de.po
packages/thuban/branches/upstream/current/po/es.po
packages/thuban/branches/upstream/current/po/fr.po
packages/thuban/branches/upstream/current/po/hu.po
packages/thuban/branches/upstream/current/po/it.po
packages/thuban/branches/upstream/current/po/pt_BR.po
packages/thuban/branches/upstream/current/po/ru.po
packages/thuban/branches/upstream/current/po/thuban.pot
packages/thuban/branches/upstream/current/setup.cfg
packages/thuban/branches/upstream/current/setup.py
packages/thuban/branches/upstream/current/test/
packages/thuban/branches/upstream/current/test/README
packages/thuban/branches/upstream/current/test/localessupport.py
packages/thuban/branches/upstream/current/test/mockgeo.py
packages/thuban/branches/upstream/current/test/postgissupport.py
packages/thuban/branches/upstream/current/test/runtests.py
packages/thuban/branches/upstream/current/test/support.py
packages/thuban/branches/upstream/current/test/test_base.py
packages/thuban/branches/upstream/current/test/test_baserenderer.py
packages/thuban/branches/upstream/current/test/test_classgen.py
packages/thuban/branches/upstream/current/test/test_classification.py
packages/thuban/branches/upstream/current/test/test_classmapper.py
packages/thuban/branches/upstream/current/test/test_color.py
packages/thuban/branches/upstream/current/test/test_command.py
packages/thuban/branches/upstream/current/test/test_connector.py
packages/thuban/branches/upstream/current/test/test_csv_table.py
packages/thuban/branches/upstream/current/test/test_dbf_table.py
packages/thuban/branches/upstream/current/test/test_derivedshapestore.py
packages/thuban/branches/upstream/current/test/test_export.py
packages/thuban/branches/upstream/current/test/test_fileutil.py
packages/thuban/branches/upstream/current/test/test_hittest.py
packages/thuban/branches/upstream/current/test/test_label.py
packages/thuban/branches/upstream/current/test/test_layer.py
packages/thuban/branches/upstream/current/test/test_lib_version.py
packages/thuban/branches/upstream/current/test/test_load.py
packages/thuban/branches/upstream/current/test/test_load_0_2.py
packages/thuban/branches/upstream/current/test/test_load_0_8.py
packages/thuban/branches/upstream/current/test/test_load_0_9.py
packages/thuban/branches/upstream/current/test/test_load_1_0.py
packages/thuban/branches/upstream/current/test/test_map.py
packages/thuban/branches/upstream/current/test/test_memory_table.py
packages/thuban/branches/upstream/current/test/test_menu.py
packages/thuban/branches/upstream/current/test/test_mockgeo.py
packages/thuban/branches/upstream/current/test/test_postgis_db.py
packages/thuban/branches/upstream/current/test/test_postgis_session.py
packages/thuban/branches/upstream/current/test/test_proj.py
packages/thuban/branches/upstream/current/test/test_range.py
packages/thuban/branches/upstream/current/test/test_save.py
packages/thuban/branches/upstream/current/test/test_scalebar.py
packages/thuban/branches/upstream/current/test/test_selection.py
packages/thuban/branches/upstream/current/test/test_session.py
packages/thuban/branches/upstream/current/test/test_shapefilestore.py
packages/thuban/branches/upstream/current/test/test_stringrepresentation.py
packages/thuban/branches/upstream/current/test/test_transientdb.py
packages/thuban/branches/upstream/current/test/test_viewport.py
packages/thuban/branches/upstream/current/test/test_wellknowntext.py
packages/thuban/branches/upstream/current/test/test_wxproj.py
packages/thuban/branches/upstream/current/test/test_xmlsupport.py
packages/thuban/branches/upstream/current/test/xmlsupport.py
packages/thuban/branches/upstream/current/thuban.py
packages/thuban/tags/
Log:
[svn-inject] Installing original source of thuban
Added: packages/thuban/branches/upstream/current/COPYING
===================================================================
--- packages/thuban/branches/upstream/current/COPYING 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/COPYING 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Added: packages/thuban/branches/upstream/current/ChangeLog
===================================================================
--- packages/thuban/branches/upstream/current/ChangeLog 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/ChangeLog 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,12521 @@
+2007-03-13 Bernhard Reiter <bernhard at intevation.de>
+
+ More release preparations: Translation string updated. Release date
+ added.
+
+ * po/*: Updated .po files with new strings.
+
+ * po/de.po: Completed German translation (3 missing, one fuzzy).
+
+ * README: Bumped minium requirement of pysqlite to 1.0.1 (as I believe
+ Thuban was tested with on Debian.)
+
+ * NEWS: New phrasing for "changes up to". Added release date.
+
+ * Thuban/UI/about.py: Added fileencoding information, otherwise
+ xgettext from 0.16.1 did not want to run on this file.
+
+ * Thuban/UI/__init__.py: Calling wx.Locale() with with parameter
+ wx.LANGUAGE_DEFAULT now. Without this change no message catalog is
+ loaded in wxPython 2.6.3.2.1.5 and thus the translation would not work.
+
+ * setup.cfg: Change tarball compression from gzip to bzip2.
+
+ * packaging/debian: Moved the directory in here from toplevel,
+ because there could be several debian packaging dirs and this
+ is outdated.
+
+ * MANIFEST.in: Added toplevel ChangeLog to distribution.
+ Made sure that files under packaging are actually packaged.
+
+2007-02-26 Bernhard Reiter <bernhard at intevation.de>
+
+ * MANIFEST.in: Added *.xmi to Doc so that ThubanModel.xmi is included.
+
+ * Extensions/svgexport/TODO: Added findings about how to write raster
+ in SVG.
+
+ * Extensions/svgexport/svgmapwriter.py: untabified two lines.
+ Fixed a typo.
+
+ * Doc/ThubanModel.xmi: Updated the format of the umbrello file.
+ Loaded and saved with umbrello 1.3.2, manually changed the
+ codegeneration tag to be empty again and change the XMI.model
+ to not contain a local path.
+ Now umbrello 1.5.5 also opens the file without crashing.
+ Thanks to Philippe LeGrand who discovered the problem and the
+ solution and filed report 141279 on bugs.kde.org for this umbrello
+ problem.
+
+2007-02-21 Didrik Pinte <dpinte at itae.be>
+
+ * Extensions/umn_mapserver/__init__.py : UTF8 locales bugfix
+
+2007-02-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/version.py, setup.py: Getting ready for release 1.2.0.
+ Using this version number.
+
+ * Doc/README: fixed a typo.
+
+ * Doc/technotes/release_process.txt: Updated. Reference platform
+ is Debian Etch now. If windows, it should be window XP.
+ Marked a few entries in the instructions as "Old:".
+
+ * README: Bumped requirements to wxWidgets 2.6.3.2 and gdal 1.3.2..
+ Added urls for homepage and infrastructure on wald. Fixed a typo.
+
+ * MANIFEST.in: Added subdir "packaging" which should be in the tarball.
+
+ * NEWS: Completed changes from 1.1.0 until today as gathered from
+ the Changelog entries. Added small section about OGR known problems
+ because we do not have a release-notes file so far.
+
+ * Doc/manual/thuban-manual.xml: Removed the installation instructions
+ as they are outdated and they should be only in one place.
+ Bumped version number of the document to 1.2.0. Marked it as Draft
+ in the title.
+
+ * Extensions/svgexport/: Get ready for release. Bump version
+ number to 1.0.1. Adjusted numbers in TODO.
+
+ * Thuban/UI/about.py: Reworked the about text. It shows now
+ when somebody was active on Thuban. Added a list of maintainers.
+ Bernhard Reiter is the current maintainer, following up on Bernhard
+ Herzog.
+
+ * Extensions/export_shapefile/export_shapefile.py: untabify.
+
+ * test/README: Added example how to set the PATH for postgis on
+ Debian Etch.
+
+2007-01-13 Didrik Pinte <dpinte at itae.be>
+
+ bboxdump, gns2shp, importAPR, mouseposition, ogr, profiling, svgexport
+ extensions migrated to wxPython 2.6
+
+ * Extensions/bboxdump/bboxdump.py:
+ updated wx statements
+
+ * Extensions/gns2shp/gns2shp.py:
+ updated wx statements
+
+ * Extensions/importAPR/importAPR.py:
+ updated wx statements
+
+ * Extensions/mouseposition/mouseposition.py:
+ updated wx statements
+
+ * Extensions/ogr/
+ ogrdialog.py, ogrstart.py:
+ updated wx statements
+
+ * Extensions/profiling/profiling.py:
+ updated wx statements
+
+ * Extensions/svgexport/
+ maplegend.py, svgsaver.py:
+ updated wx statements
+
+
+2007-01-08 Didrik Pinte <dpinte at itae.be>
+
+ export_shapefile extension migrated to wxPython 2.6
+
+ * Extensions/export_shapefile/export_shapefile.py:
+ updated wx statements, changed the FileDialog to wx.SAVE (was wx.OPEN)
+
+2007-01-08 Didrik Pinte <dpinte at itae.be>
+
+ umn_mapserver extension migrated to wxPython 2.6
+
+ * Extensions/umn_maserver/
+ mf_handle.py, mf_import.py, mf_export.py:
+ update wx imports to 2.6 policy
+
+2007-01-06 Didrik Pinte <dpinte at itae.be>
+
+ UTF-8 locales support reading non utf-8 files.
+ This is a workaround and not a real bugfix. See
+ http://wald.intevation.org/tracker/index.php?func=detail&aid=118
+ for more details
+
+ * Thuban/UI/tableview.py, controls.py, baserenderer.py, view.py:
+ decode text from iso-8859-1 encoding.
+
+2007-01-01 Bernhard Reiter <bernhard at intevation.de>
+
+ * test/postgissupport.py, test/test_postgis_db.py: adding an
+ explicit WITH OIDS to the create table commands. This fixes tests
+ that rely on an oid column to be present for postgresql >=8.0.
+ Thanks for Frank Koormann for the hint.
+
+2006-11-06 Didrik Pinte <dpinte at itae.be>
+
+ * libraries/thuban/wxproj.cpp: bugfix - allow compilation with
+ msvc++ toolkit 2003
+
+2006-11-06 Bernhard Reiter <bernhard at intevation.de>
+
+ Made it easier to run PostGIS test on Debian Etch. Improving
+ https://wald.intevation.org/tracker/index.php?func=detail&aid=173 .
+
+ * test/postgissupport.py: Taking pg_ctl and initdb commands
+ from internal variables now. Adding deactivated example values
+ for Debian Etch.
+ find_postgis_sql(): Added special line for Debian Etch postgresql-8.1.
+ Added copyright year 2006.
+
+2006-10-25 Bernhard Reiter <bernhard at intevation.de>
+
+ Moved ogr Extension to Extension menu.
+
+ * Extensions/ogr/
+ __init__.py, ogrstart.py, ogrshapes.py, ogrdialog.py
+ test/test_OGRShapestore.py, test/__init__.py:
+ adding encoding information and made sure Autor's names
+ with an umlaut are actually written with an umlaut.
+
+ * Extensions/ogr/ogrstrat.py: now registering in menu "Extensions",
+ having a "(testing)" string before the submenu to prepare for 1.2.0
+ release. Bumped copyright year to 2006.
+
+2006-10-15 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/renderer.py: Added module variable verbose and
+ added verbose output before doing a raster projection.
+ Minor: Added (c) year 2006.
+
+ * test/test_baserenderer.py: Added new function
+ test_projected_raster_decimalcommalocale()
+ Added new author Bernhard Reiter and new copyright year 2006.
+
+ * libraries/thuban/gdalwarp.cpp(ProjectRasterFile): Adding
+ switching to LC_NUMERIC "C" and back before calling GDAL functions -
+ only #if python >=2.4 .
+
+2006-10-10 Didrik Pinte <dpinte at itae.be>
+
+ Win32 build updates
+
+ * setup.py :
+ - update to the latest libs for win32 setup tasks
+ - added gdal and Lib content to the inno setup build task
+ - added stable and experimental extensions to setup packages
+
+ * thuban.py :
+ - gdal support for win32 inno installation
+
+2006-10-10 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/Model/layer.py (Layer.GetLabelPosFromShape): new method
+ extracted from Thuban/UI/viewport.py
+ * Thuban/UI/viewport.py (Viewport.LabelShapeAt): uses new method
+
+2006-09-28 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/UI/classgen.py: bugfix due to wx2.6 update
+
+ * Thuban/UI/view.py: removed non needed declaration
+
+ * Thuban/UI/selection.py : typo correction
+
+2006-09-24 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/Model/proj.py(_do_we_have_to_work_around_broken_proj):
+ Making the test more robust for observed python 2.3 problems
+ with setlocale().
+
+ * test/runtests.py: Added new option ---setdecimalcommalocale
+ to run all tests with an LC_NUMERIC that uses comma as decimal_point.
+ Minor: Added (c) year 2006. Fixed typo in a docstring.
+
+ * test/test_transientdb.py: Minor: Added (c) year 2006. Fixed typo in
+ a docstring.
+
+2006-09-23 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/ogr/test/test_OGRShapestore.py: fixed skip_if_no_ogr()
+ and added it to TestOGRTable.setUp() so that all tests get skipped
+ if ogr cannot be imported. Added (c) year 2006.
+
+2006-09-18 Didrik Pinte <dpinte at itae.be>
+
+ * wxPython 2.6 update : wx 2.4 syntax has been updated to 2.6
+
+2006-09-18 Bernhard Reiter <bernhard at intevation.de>
+
+ Fixed proj behaviour with python >=2.4 when decimal_point != '.'.
+
+ * Thuban/UI/application.py: Fixed warning dialog when gdal is missing.
+
+ * test/test_proj.py: new test_lc_numeric_robustness(). Added author
+ Bernhard Reiter and new copyright year 2006.
+
+ * Thuban/Model/proj.py: New _do_we_have_to_work_around_broken_proj()
+ and Projection.assuregoodlocale(), Projection.assureinitlocale().
+ Added author Bernhard Reiter and (c) 2006.
+
+2006-09-15 Bernhard Reiter <bernhard at intevation.de>
+
+ * README: added RXP and pyRXP as optional for tests.
+
+ * test/localessupport.py: New. Contains a helper function
+ to find a locale with comma used as decimal_point.
+
+2006-08-31 Bernhard Reiter <bernhard at intevation.de>
+
+ * README: fixed URLs to sqlite and pysqlite.
+
+ * Thuban/UI/about.py: Added Didrik Pinte as contributor. Extended
+ copyright range to include 2006.
+
+2006-06-29 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/UI/main.py: circular import fix.
+
+2006-06-27 Frank Koormann <frank at intevation.de>
+
+ New Classification "Pattern": Classify text attributes by regexp.
+
+ * Thuban/Model/classification.py (class ClassGroupPattern):
+ New, group is associated with a regular expression.
+ (Classification._compile_classification): Store compiled regexp and
+ original group for pattern.
+ (Classification.FindGroup): Added pattern.
+
+ * Thuban/UI/classifier.py
+ (ClassGrid._OnLabelRightClicked, ClassGrid.labelPopup):
+ New, add popup to select singleton/pattern.
+ (ClassTable.GetRowLabelValue, ClassTable.GetValueAsCustom,
+ ClassTable.SetValueAsCustom): Added pattern.
+ (ClassTable.__ParseInput): Autodetect singleton/pattern.
+
+ * Thuban/Model/save.py (SessionSaver.write_classification):
+ Added pattern.
+
+ * Thuban/Model/load.py (SessionLoader.start_clpattern,
+ SessionLoader.end_clpattern): New, process pattern elements.
+
+ * test/test_classification.py (class TestClassGroupPattern): New.
+ (TestClassification.test_add_pattern,
+ TestClassification.test_multiple_groups_textual,
+ TestClassification.test_deepcopy_textual): New.
+ (TestClassification.test_multiple_groups_numerical):
+ Renamed test_multiple_groups.
+ (TestClassification.test_deepcopy_numerical): Renamed test_deepcopy.
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer):
+ Added pattern.
+
+ * test/test_load.py (ClassificationTest.TestLayers, TestClassification):
+ Added pattern.
+
+ * test/test_layer.py
+ (TestLayerModification.test_set_classification_textual): New
+ (TestLayerModification.test_set_classification_numerical):
+ Renamed test_set_classification.
+
+ * Doc/manual/thuban-manual.xml: Added pattern to layer classification
+ description.
+
+ * Resources/XML/thuban-1.1.dtd: Added clpattern element and attribs.
+
+2006-06-29 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/version.py: Bugfix determination of SQLite, the wright one !
+
+2006-06-28 Didrik Pinte <dpinte at itae.be>
+
+ * packaging/windows/thubanstart.py: sample file loading all the stable
+ extensions
+
+2006-06-28 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/version.py: Bugfix determination of SQLite on old and recent
+ systems (support pysqlite1 and pysqlite2)
+
+2006-06-27 Frank Koormann <frank at intevation.de>
+
+ * Thuban/version.py: Bugfix determination of SQLite on old systems.
+
+2006-05-17 Didrik Pinte <dpinte at itae.be>
+ * Extensions/ogr/__init__.py : updated test for win32 and correct
+ imports
+
+2006-05-15 Didrik Pinte <dpinte at itae.be>
+ Ashamed ... still some tabs in the files
+
+ * Thuban/version.py : tabs removed
+ * Thuban/Model/transientdb.py : tabs removed
+
+2006-05-15 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/version.py : coding style correction
+ * Thuban/Model/transientdb.py : coding style correction
+
+2006-05-15 Didrik Pinte <dpinte at itae.be>
+
+ * Thuban/version.py : Updated imports to support pysqlite2
+
+ * Thuban/Model/transientdb.py : Updated imports to support pysqlite2
+ Patched the querying system to support the param style of pysqlite2
+
+2006-04-24 Didrik Pinte <dpinte at itae.be>
+
+ * Extensions/svgexport/__init__.py: The extension now works on win32
+ architecture. Bug #87 corrected.
+
+2006-04-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Doc/technotes/coding_guidelines.txt: Changed text from CVS to SVN.
+ Removed emacs specific hint and replaced it with a general hint
+ that editors might support writing changelogs.
+
+2006-04-12 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/version.py: Changed thuban_release mechanism to use "svn"
+ instead of "cvs".
+
+2006-03-31 Bernhard Reiter <bernhard at intevation.de>
+
+ * libraries/thuban/wxproj.cpp: including proj_api.h instead of
+ projects.h now. According the Frank Warmerdam and man pj_init
+ this is the public interface to proj. Thus I have changed PJ to projPJ.
+ And I could remove the hack to avoid clashes with typedef PVALUE
+ and #define LP in projects.h clashing with symbols when trying to
+ build on windows. The file is cleaner and nicer now.
+
+2006-03-29 Bernhard Reiter <bernhard at intevation.de>
+
+ * libraries/thuban/wxproj.cpp: undef LP to avoid clash when
+ trying to build with mingw.
+
+2005-10-18 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/about.py: remove unused import of getdefaultlocale.
+ Added display of internal encoding to the about dialog text.
+
+ * Extensions/svgexport/__init__.py: changed version to "1.0.0+cvs".
+
+2005-10-18 Bernhard Reiter <bernhard at intevation.de>
+
+ Startup improved: We fail right away if the internal encoding could
+ not be determined.
+
+ * Thuban/__init__.py (get_internal_encoding): new.
+
+ * test/test_stringrepresentation.py (class TestInternalEncoding):
+ Preserve the internal encoding for the tests in this class.
+
+2005-10-17 Bernhard Reiter <bernhard at intevation.de>
+
+ * test/test_stringrepresentation.py: New file, for now testing
+ that set_internal_coding() is throwing an exception for bad exceptions.
+
+ * Thuban/__init__.py (set_internal_encoding): added a forwards
+ and backward translation, so that we fail early if the
+ internal_encoding is bad.
+
+2005-10-17 Bernhard Reiter <bernhard at intevation.de>
+
+ svgexport 1.0.0cvs: Fixed ARC layer writing: No filling is done.
+ You could actually get polylines with filling in between,
+ when the classification for the lines had a fill color.
+ E.g. this happens when you generate a classification from a ramp.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ New test_export_arc_no_fill(). Extend copyright notice to 2005.
+
+ * Extensions/svgexport/svgmapwriter.py
+ (SVGRenderer.draw_shape_layer_incrementally()):
+ Setting TRANSPARENT_BRUSH for shaptype ARC.
+ Extend copyright notice to 2005.
+
+ * Extensions/svgexport/__init__.py: Extend copyright notice to 2005.
+
+2005-09-08 Frank Koormann <frank at intevation.de>
+
+ * Doc/manual/thuban-manual.xml (Map Management): Fixed typo reported
+ by Erik (sigra.at.home.se)
+
+2005-08-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_selection_incrementally):
+ Call the right method for the default size.
+
+2005-08-11 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/export_shapefile: New.
+
+ * Extensions/export_shapefile/__init__.py: New. Initialize
+ the export_shapefile extension.
+
+ * Extensions/export_shapefile/export_shapefile.py: New.
+ Exports a layer as a Shapefile.
+
+2005-08-08 Jan-Oliver Wagner <jan at intevation.de>
+
+ * po/de.po: String fixes. This fixes Debian bug #313843.
+
+2005-07-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ Remove the attributes from the layer element in
+ .thuban files for the save routine.
+ This also solves RT bug #3149,
+ https://intevation.de/rt/webrt?serial_num=3149
+
+ * test/test_load.py: (TestSingleLayer, TestNonAsciiColumnName,
+ TestLayerVisibility, TestSymbolSize, TestClassification, TestLabels,
+ TestLayerProjection, TestJoinedTable, TestLabelLayer): Removed
+ attributes from layer element to classification clnull element.
+
+ * test/test_save.py (SaveSessionTest.testSingleLayer,
+ SaveSessionTest.testLayerProjection,
+ SaveSessionTest.testClassifiedLayer,
+ SaveSessionTest.test_joined_table, SaveSessionTest.test_save_postgis):
+ Removed attributes from layer element to classification clnull element.
+ (test_save_postgis.NonConnectionStore._fetch_table_information):
+ added pretending to have a shape_type.
+
+ * Resources/XML/thuban-1.1.dtd: Make the attributes field
+ and field_type of classification optional.
+
+ * Thuban/Model/classification.py (Classification.TreeItem.build_info):
+ Added output of size.
+
+ * Thuban/Model/load.py (SessionLoader.start_classification):
+ Change attribute 'field' and 'field_type' from obligatory to
+ optional to allow empty classes (ie. only with a default=clnull).
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Don't write
+ any attributes anymore for the layer element.
+ (SessionSaver.write_classification): Even if there is no
+ classification field, still write the classification because
+ the clnull (default) symbol will not be defined anymore as
+ part of the layer element.
+
+2005-07-05 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (setup call): Version 1.1.0
+
+ * NEWS: Update for 1.1.0
+
+ * MANIFEST.in: Add *.txt to files taken from Doc. Otherwise the
+ technores won't be included
+
+ * Thuban/UI/about.py (About.__init__): Extend copyright notice to
+ 2005
+
+ * po/de.po: Updated.
+
+2005-07-05 Bernhard Herzog <bh at intevation.de>
+
+ * README: gdal 1.1.8 is too old. 1.2.5 works.
+
+2005-07-05 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/XML/thuban-1.1.dtd (rasterlayer): Add the opacity and
+ masktype attributes.
+
+2005-07-05 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.__mangle_bounding_box)
+ (Layer.ClipBoundingBox): Rename ClipBoundingBox to
+ __mangle_bounding_box. See the comments in the code and RT #2845
+
+ * test/test_layer.py (TestLayer.test_arc_layer_with_projection):
+ Remove the explicit test of ClipBoundingBox. The method isn't
+ public anymore and the direct call in the test wasn't necessary in
+ the first place. If ClipBoundingBox (now __mangle_bounding_box)
+ isn't called, the return value of ShapesInRegion will be
+ different.
+
+2005-07-05 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/viewport.py (ViewPort.set_view_transform): Handle
+ ZeroDivisionError exceptions. I don't know when they happen
+ exactly. It probably happens when the projections aren't set
+ properly.
+
+2005-07-01 Bernhard Herzog <bh at intevation.de>
+
+ First step towards unicode. With this roughly we're at step 1
+ string_representation.txt
+
+ * Doc/technotes/string_representation.txt: New. Document how
+ strings are represented in Thuban and how to get to a Unicode
+ Thuban.
+
+ * Thuban/__init__.py (set_internal_encoding)
+ (unicode_from_internal, internal_from_unicode): New. The first few
+ functions for the internal string representation
+
+ * Thuban/UI/about.py (unicodeToLocale): Removed. Use
+ internal_from_unicode instead.
+
+ * Thuban/UI/__init__.py (install_wx_translation): Determine the
+ encoding to use for the internal string representation. Also,
+ change the translation function to return strings in internal
+ representation even on unicode builds of wxPython
+
+ * Thuban/Model/load.py (SessionLoader.check_attrs): Decode
+ filenames too.
+ (SessionLoader.start_clrange): Use check_attrs to decode and check
+ the attributes.
+
+ * Thuban/Model/xmlreader.py (XMLReader.encode): Use
+ internal_from_unicode to convert unicode strings.
+
+ * Thuban/Model/xmlwriter.py (XMLWriter.encode): Use
+ unicode_from_internal when applicable
+
+ * test/runtests.py (main): New command line option:
+ internal-encoding to specify the internal string encoding to use
+ in the tests.
+
+ * test/support.py (initthuban): Set the internal encoding to
+ latin-1
+
+ * test/test_load.py (TestSingleLayer.test, TestClassification.test)
+ (TestLabelLayer.test): Use the internal string representation when
+ dealing with non-ascii characters
+
+ * test/test_load_1_0.py (TestSingleLayer.test)
+ (TestClassification.test, TestLabelLayer.test): Use the internal
+ string representation when dealing with non-ascii characters
+
+ * test/test_load_0_9.py (TestSingleLayer.test)
+ (TestClassification.test): Use the internal string representation
+ when dealing with non-ascii characters
+
+ * test/test_load_0_8.py (TestUnicodeStrings.test): Use the
+ internal string representation when dealing with non-ascii
+ characters
+
+ * test/test_save.py (XMLWriterTest.testEncode)
+ (SaveSessionTest.testClassifiedLayer): Use the internal string
+ representation when dealing with non-ascii characters where
+ applicable
+
+2005-06-30 Bernhard Herzog <bh at intevation.de>
+
+ * test/runtests.py: Untabify.
+
+2005-06-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_selection_incrementally):
+ untabify.
+
+2005-06-30 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/ogr/test/__init__.py: Add missing coding directive
+
+2005-06-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_selection_incrementally):
+ Use the default size for rendering selected items of default type.
+ Fixes part 2 of https://intevation.de/rt/webrt?serial_num=3149
+
+2005-06-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/importAPR/apr.py (APR_BShSym): Extend by 'Stripple'.
+ (APR_TClr.GetThubanColor): Fix bug in color interpretation.
+ Thanks to Frank Koormann who identified this problem.
+
+ * Extensions/importAPR/importAPR.py (APR_VShSym): New. Just
+ another symbol identified.
+
+2005-06-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2005-05-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/projdialog.py: Add missing import, which led to an
+ exception when opening a layer's projection.
+
+2005-05-09 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (FileLoadTestCase.filename): Fix doc-string.
+
+2005-05-09 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (PostGISConnection.connect): Set the
+ connection to autoconnect. Fixes RT#3148.
+
+ * test/test_postgis_db.py
+ (TestPostGISSpecialCases.test_simple_error_handling): New test
+ that attempts to reproduce RT#3148.
+
+2005-05-06 Jonathan Coles <jonathan at intevation.de>
+
+ Add support for saving and loading the opacity and mask type
+ properties of RasterLayers. Also add support for proper use
+ of alpha information while drawing images not in 'RAW' format.
+ If transparency in an image format (e.g, PNG) is supported by
+ wxWidgets then the image would previously have been draw with
+ transparent regions, but the opaque regions would have been
+ unaffected by a change in the layer's opacity. This patch
+ corrects the problem.
+
+ * Thuban/Model/layer.py (RasterLayer): Added opacity and
+ masktype parameters to the constructor, and set the
+ appropriate variables to those values.
+
+ * Thuban/Model/load.py (SessionLoader.start_rasterlayer): Added
+ code to read the opacity and mask type of the layer and construct
+ a new layer with the additional parameters.
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Added code
+ to save the opacity and mask type of a layer.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_layer): Pass
+ the opacity of the layer to draw_raster_data rather than the layer.
+ (BaseRenderer.draw_raster_data): Remove the layer parameter because
+ the function doesn't need to know about the layer. Add the optional
+ opacity parameter whose default is 1.0. Add 'PNG' as a supported
+ graphics format.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): Fixed
+ signature to match that in BaseRenderer. Use the new opacity argument
+ in place of calling layer.Opacity(). In the case where the
+ format is not 'RAW', alpha_data is None and the loaded image has
+ alpha information, use the file's alpha information. This is
+ still subject to the layer's opacity setting.
+
+ * test/test_baserenderer.py (SimpleRenderer.draw_raster_data):
+ Fixed signature to match that in BaseRenderer.
+
+ * test/test_load.py (TestRasterLayer): Change file_contents to
+ include opacity and masktype variables.
+ (TestRasterLayer.test): Include tests for opacity and masktype
+ changes.
+
+ * test/test_save.py (SaveSessionTest.testRasterLayer): Restructure
+ test to cover a variety of combinations of masktype and opacity
+ settings.
+
+2005-05-02 Jan-Oliver Wagner <jan at intevation.de>
+
+ * debian/rules: add --use-wx-python-swig-hack
+ to the build command.
+ Thanks to Moritz Lennert for pointing this out.
+
+2005-04-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introduce OGRFileShapeStore in ogr extension.
+ This allows at least that loaded shapefile shape stores
+ can be saved correctly in the thuban session file
+ and reloaded again (reload is via core shapefile
+ routine, not OGR). For other types, .thuban files
+ can not be reloaded for the time being.
+
+ * Extensions/ogr/ogrshapes.py (OGRFileShapeStore): New. This
+ class ist to be used for any file-based shape stores
+ accessed through OGR.
+
+ * Extensions/ogr/ogrstart.py (open_with_ogr): Added
+ forgotten _ for i18n. Adapted call OpenFileShapestore
+ regarding new parameter.
+ (OpenFileShapestore): Use OGRFileShapeStore instead of
+ OGRShapeStore. Fix return value (None instead of null).
+ Add new parameter "mainwindow" to avoid accessing global
+ context.
+
+2005-04-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introduce FileShapeStore as generalization for
+ file-based shape stores. In a first instance
+ this allows additional modules to handle shapefile
+ format as well, namely the OGR extension.
+
+ * Thuban/Model/data.py: Various small fixes in doc-strings.
+ (FileShapeStore): New class.
+ (ShapefileStore): Derive from FileShapeStore.
+ (ShapefileStore.__init__): Call __init__ of FileShapeStore,
+ rename self.table to self._table, initialize self._bbox
+ (ShapefileStore._open_shapefile): Use self._bbox instead of self.bbox
+ and self.FileName() instead of self.filename.
+ (ShapefileStore.Table): Use self._table instead of self.table.
+ (ShapefileStore.FileName): Removed (moved to FileShapeStore).
+ (ShapefileStore.BoundingBox): Use self._bbox instead of self.bbox.
+
+ * Thuban/Model/save.py: Replace ShapefileStore by FileShapeStore.
+ (SessionSaver.write_data_containers): Only use methods of the
+ base class FileShapeStore.
+
+2005-04-26 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/wms.py (render_wms_layer): Adjusted the render
+ function to the modified render engine
+
+2005-04-25 Martin Schulze <joey at infodrom.org>
+
+ * Thuban/UI/renderer.py (MapRenderer.projected_raster_layer):
+ Added a description according to the CVS log message
+
+2005-04-23 Martin Schulze <joey at infodrom.org>
+
+ * Thuban/UI/renderer.py: Added a missing import
+
+2005-04-23 Russell Nelson <nelson at crynwr.com>
+
+ * Thuban/UI/view.py (MapCanvas.OnMiddle{Up,Down}): Changed the
+ way the previous tool is remembered, so that middle-button
+ panning works even if you haven't selected a tool.
+
+2005-04-11 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/thuban/wxproj.cpp: Move the compatibility code that
+ deals with the wxPython 2.4 version of wxPython.h into the #ifdef
+ branch that includes wxPython.h because it's only needed when
+ wxPython.h is used. Also, it won't compile when
+ USE_WX_PYTHON_SWIG_HACK is set otherwise.
+
+2005-04-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classifier.py (ClassGrid.__init__): Use -1 as the ID.
+ (ID_CLASS_TABLE): Removed. It wasn't used anywhere except in
+ ClassGrid.__init__ and it's value is outside of the valid
+ range (must be < 32768). wxPython 2.5 complains about it with an
+ exception.
+
+2005-04-05 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2005-04-05 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/thuban/wxproj.cpp: Make it work with a wxPython.h from
+ wxPython 2.4 as well. Also, remove a now obsolete comment.
+
+2005-04-05 Bernhard Herzog <bh at intevation.de>
+
+ Use wxPython.h by default but provide a workaround when it isn't
+ available.
+
+ * setup.py (wxproj_extension): New variable. Assign the Extension
+ instance for Lib.wxproj to this variable instead of putting it
+ directly into the listso that it can be accessed by other code
+ later.
+ (thuban_build_ext.user_options): Added boolean option
+ --use-wx-python-swig-hack.
+ (thuban_build_ext.initialize_options): Initialize the new option
+ to False.
+ (thuban_build_ext.finalize_options): If the new option was given,
+ define the preprocesser macro USE_WX_PYTHON_SWIG_HACK.
+ (thuban_build_ext): Update the doc-string
+
+ * libraries/thuban/wxproj.cpp: Normally we use
+ wx/wxPython/wxPython.h now. Only if USE_WX_PYTHON_SWIG_HACK is
+ defined, use swigPtrConvertHack.h instead.
+
+ * libraries/thuban/swigPtrConvertHack.h: Remove the code that was
+ copied over from wxPython.h.
+ (decode_pointer_new): New. Equivalent of decode_pointer for
+ wxPython 2.5.
+ (wxPyConvertSwigPtr): Modified to cope with wxPython 2.5 as well.
+
+ * README: Add section on potential build problems which explains
+ how the work-around for a missing wxPython.h is activated.
+
+2005-03-29 Bernhard Herzog <bh at intevation.de>
+
+ * test/postgissupport.py (find_postgis_sql): Added yet another
+ potential location for (lw)postgis.sql because the file has moved
+ again in postgis 1.0.0 rc4.
+
+2005-03-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/legend.py (BMP_SIZE_W, BMP_SIZE_H): Set both to 16 to
+ match the site of the legend_icon_layer icon. Otherwise wxpython
+ 2.5 complains when the legend is created with the error:
+
+ PyAssertionError: C++ assertion "(bitmap.GetWidth() == m_width &&
+ bitmap.GetHeight() == m_height) || (m_width == 0 && m_height ==
+ 0)" failed in ./src/generic/imaglist.cpp(81): invalid bitmap size
+ in wxImageList: this might work on this platform but definitely
+ won't under Windows.
+
+2005-03-23 Jonathan Coles <jonathan at intevation.de>
+
+ These changes add support for adjusting the opacity of a raster layer.
+
+ * Thuban/Model/layer.py (RasterLayer.Opacity): Replaces AlphaOpacity.
+ (RasterLayer.SetOpacity): Replaces SetAlphaOpacity. Also triggers
+ a LAYER_CHANGED event if the opacity actually changes.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_data): Added
+ layer parameter needed in the implementation of this method in
+ renderer.py.
+
+ * Thuban/UI/layerproperties.py (LayerProperties.dialog_layout): Fixed
+ typo 00 -> 0.
+
+ * Thuban/UI/rasterlayerproperties.py (RasterLayerProperties): Added
+ control to adjust opacity.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): Scale the
+ alpha data based on the opacity level of the layer.
+
+ * test/test_baserenderer.py (SimpleRenderer.draw_raster_data): Now
+ accepts a layer parameter.
+
+ * test/test_layer.py (TestLayerModification.test_raster_layer):
+ Rename opacity method calls and add test for LAYER_CHANGED.
+
+2005-03-16 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_connector.py (DeletionTestMixin.check_deletions)
+ (DeletionTestMixin.check_deletetions): renamed to check_deletions.
+ update the callers.
+
+2005-03-14 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2005-03-10 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introducing initialization callbacks for extensions.
+
+ * Thuban/UI/extensionregistry.py (ExtensionDesc.__init__): Added
+ optional parameter init_callback.
+ (ExtensionDesc.init_ext): New. Executes the callback and sets
+ a status.
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Add the
+ initialization of the extensions.
+ (ThubanApplication.init_extensions): Init all extensions.
+
+ * Thuban/UI/about.py (About.__init__): Added status of the extensions
+ to the about text.
+
+ * Extensions/gns2shp/__init__.py: Added init method for Extension
+ description.
+ (init): New. Contains the initialization of the module.
+
+2005-03-04 Nina Hüffmeyer <nhueffme at intevation.de>
+
+ * Extensions/ogr/ogrdialog.py: Added a dialog, which asks for
+ OGRConnection to open a datasource. Removed dialog to display all
+ available drivers. Added some doc strings.
+
+ * Extensions/ogr/ogrstart.py: Added menu entry for opening an
+ OGRDatasource with a string. Added two opening methods which return an
+ OGRDatasource (either data from file or from DB).
+
+ * Extensions/ogr/ogrshapes.py: Added class OGRGeometry, which
+ represents a geometry reference of an OGRFeature. OGRShape now has a
+ list of referenced geometry objects (important for geometry
+ collections).
+ For OGRShapeStores loaded from a DB an ID column can be specified now.
+
+2005-02-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ * test/test_map.py (TestMapWithContents.test_tree_info):
+ Added label layer for comparison.
+
+2005-02-18 Jonathan Coles <jonathan at intevation.de>
+
+ * libraries/thuban/gdalwarp.cpp (GetImageData): Optimize the loop
+ which builds a mask. Handle the majority of an image in a loop,
+ creating 8 bits at a time. Later, handle the edge case where less
+ than 8 bits are packed.
+
+2005-02-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_baserenderer.py (TestBaseRenderer.setUp): Fix
+ doc-string
+
+2005-02-18 Jonathan Coles <jonathan at intevation.de>
+
+ * setup.py: Remove wx_cs_params from gdal compile options.
+
+2005-02-18 Jonathan Coles <jonathan at intevation.de>
+
+ Refactored baserenderer.py and renderer.py to remove baserenderer.py's
+ dependencies on wxPython. Added a new method projected_raster_layer()
+ that returns a raster layer image in projected space. This must be
+ implemented in classes derived from BaseRenderer. This also eliminates
+ the dependency on gdal in baserenderer.py.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_layer): Call
+ new projected_raster_layer() to get projected raster image instead
+ of directly calling ProjectRasterFile().
+ (BaseRenderer.projected_raster_layer): New. This must be implemented
+ by derived classes. It takes almost the same arguments as ProjectRasterFile
+ did and returns a projected image with mask and alpha data (if requested).
+ (BaseRenderer.render_map_incrementally): Remove the check for gdal since
+ that check will be done in MapRenderer.projected_raster_layer(). This
+ also allows other implementations to use different projection code.
+
+ * Thuban/UI/renderer.py (MapRenderer.projected_raster_layer):
+ Implementation of BaseRenderer.projected_raster_layer. Checks for
+ gdal support and wxPython version. Also handles exceptions from
+ ProjectRasterFile.
+
+ * libraries/thuban/gdalwarp.cpp: Removed checks for wxPython versions
+ and added a variable which can be set through the options argument
+ of ProjectRasterFile.
+
+ * test/test_baserenderer.py (SimpleRenderer.projected_raster_layer): New.
+ Calls ProjectRasterFile and returns the result.
+ (TestBaseRenderer.test_projected_raster_layer): New. Tests the results
+ of calling projected_raster_layer() with different options.
+ (TestBaseRenderer.test_raster_no_projection): Removed tests based on
+ wxPython version and all tests of masks and alpha channels. These are
+ now in test_projected_raster_layer().
+
+2005-02-17 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/map.py, Thuban/Model/label.py: Fixed
+ doc-strings to comply with coding_guidelines.
+
+2005-02-17 Jan-Oliver Wagner <jan at intevation.de>
+
+ Docstring improvements and minor fixes for labellayer.
+
+ * Thuban/Model/map.py:
+ (Map, Map.Destroy, Map.RemoveLayer, Map.ClearLayers,
+ Map.Layers, Map.HasLayers, Map.MoveLayerToTop,
+ Map.RaiseLayer, Map.LowerLayer, Map.MoveLayerToBottom,
+ Map.ProjectedBoundingBox, Map.GetProjection): Improved/added
+ doc string.
+ (Map.BoundingBox): Removed superfluous test for label_layer
+ and improved doc string.
+ (Map.TreeInfo): Added label_layer and improved sdo string.
+
+ * Thuban/Model/label.py: Added import of _.
+ (Label, Label.__init__): Improved/added doc string.
+ (LabelLayer, LabelLayer.__init__, LabelLayer.Labels,
+ LabelLayer.RemoveLabel, LabelLayer.ClearLabels):
+ Improved/added doc string.
+ (LabelLayer.AddLabel): Use already defined names for
+ align strings and improved doc string.
+ (LabelLayer.TreeInfo): New. Return the object data for
+ the tree view.
+
+2005-02-16 Jonathan Coles <jonathan at intevation.de>
+
+ Further wxPython 2.5 changes using patches from Daniel Calvelo Aros
+ so that that wxproj doesn't crash. Added GUI support for selecting
+ alpha channel (opacity can't be selected yet).
+
+ NOTE: If wxPython.h is including in future distribution packages
+ then it will not be necessary to have the files swigPtrConvertHack.h
+ and wxPython_int.h included with Thuban. This is hopefully
+ a temporary workaround.
+
+ * setup.py (thuban_build_ext.finalize_options): gdalwarp needs
+ access to the macro wxCHECK_VERSION so that it will properly
+ generate a bit mask. There was a problem between wx2.4 and wx2.5
+ that this works around.
+
+ * Thuban/Model/layer.py (RasterLayer.UseMask): Removed in favor
+ of RasterLayer.MaskType.
+ (RasterLayer.SetUseMask): Removed in favor of RasterLayer.SetMaskType
+ (RasterLayer.MaskType): New. Returns the type of mask to use. Can
+ specify none, a bitmap, or an alpha channel.
+ (RasterLayer.SetMaskType): New. Set what kind of mask to use.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_layer):
+ Set the raster warping options for the mask based on the value
+ of RasterLayer.MaskType.
+
+ * Thuban/UI/legend.py (LegendTree.__FillTreeLayer): Remove
+ deprecated calls to SetItemSelectedImage in favor of SetItemImage
+ with wxTreeItemIcon_Selected.
+
+ * Thuban/UI/rasterlayerproperties.py: Support selecting to use
+ an alpha channel for the mask.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): Use alpha
+ data if it is available and an alpha channel is supported under
+ the current version of wxPython.
+
+ * libraries/thuban/gdalwarp.cpp (GetImageData): Added compiler define
+ to select whether 1's or 0's select the desired portion of an image
+ in the bit mask. wx2.4 has a bug where the documentation is the opposite
+ from behavior.
+ (ProjectRasterFile): Only generate an alpha channel if the version
+ of wxPython is >= 2.5.3.
+
+ * libraries/thuban/wxproj.cpp: Applied patches from Daniel Calvelo Aros.
+ When wxPython >= 2.5.3 use the special swig functions to decode an
+ object's address.
+
+ * libraries/thuban/swigPtrConvertHack.h: Includes conditional code
+ based on the version of wxPython. If >= 2.5.3 use the special swig
+ functions from wxPython to decode wxPython objects, otherwise use
+ the old method of retrieving the address from the object __repr__ string.
+
+ * libraries/thuban/wxPython_int.h: Copied from wxPython source.
+ Unnecessary code was removed to make it smaller.
+
+ * test/test_baserenderer.py (TestBaseRenderer.test_raster_no_projection):
+ Add tests for returning an alpha channel.
+
+ * test/test_layer.py (TestLayerModification.test_raster_layer): Fix
+ tests that used removed functions UseMask and SetUseMask
+
+
+2005-02-08 Bernhard Herzog <bh at intevation.de>
+
+ More wxPython 2.5 changes. This time taken from a patch from
+ Daniel Calvelo Aros.
+
+ * Thuban/UI/tableview.py (QueryTableFrame.__init__)
+ (QueryTableFrame.__init__): Pass the size of a spacer as a single
+ item.
+
+ * Thuban/UI/projdialog.py (ProjFrame.build_dialog)
+ (ProjFrame.build_dialog): Pass the size of a spacer as a single
+ item.
+
+ * Thuban/UI/dbdialog.py (ChooseDBTableDialog.__init__): Pass the
+ size of a spacer as a single item.
+
+ * Thuban/UI/classifier.py (Classifier.dialog_layout): Pass the
+ size of a spacer as a single item.
+
+2005-02-08 Bernhard Herzog <bh at intevation.de>
+
+ Compatibility with wxPython 2.5. The changes should make it work
+ better with 2.5 while still keeping compatibility with 2.4. There
+ are still problems with 2.5, though.
+
+ * Thuban/UI/dock.py (DockableWindow.__CreateBorder): Pass the size
+ of a spacer as a single item.
+
+ * Thuban/UI/classifier.py (ClassGroupPropertiesCtrl): Derive only
+ from wxControl
+
+ * Thuban/UI/legend.py (LegendTree): When running with wxPython <
+ 2.5, add an implementation of the GetFirstChild method that does
+ not require the second parameter.
+ (LegendTree.find_layer, LegendTree._OnMsgMapLayersAdded)
+ (LegendTree._OnMsgMapLayersRemoved, LegendTree.DeleteAllItems)
+ (LegendTree.DeleteChildren, LegendTree.__ShowHideLayer): Do not
+ pass the second parameter to GetFirstChild
+
+2005-02-08 Nina Hüffmeyer <nhueffme at intevation.de>
+
+ * Extensions/ogr/ogrshapes.py: Removed some print commands.
+
+ * Extensions/ogr/ogrstart.py: Changed the GUI. OGR is no longer an
+ additional menu but appears as a possibility in the menu Map.
+
+2005-02-07 Jonathan Coles <jonathan at intevation.de>
+ * libraries/thuban/gdalwarp.cpp: Removed the macros PYTHON_ERR
+ and PYTHON_ERRF since they were no longer necessary.
+
+2005-02-07 Bernhard Reiter <bernhard at intevation.de>
+ * Thuban/UI/classifier.py (ClassGrid.DeleteSelectedRows):
+ Enable translation for message string.
+
+2005-02-06 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/infodialog.py (wmsInfoDialog.__init__): Adjusted
+ the arguments of the contstructor to fit the global scheme
+
+2005-01-31 Nina Hüffmeyer <nhueffme at intevation.de>
+
+ * Extensions/ogr/ogrdialog.py: Added class ogrdialog.py, which provides
+ some dialogs needed to start ogr.
+
+ * Extensions/ogr/__init__.py: Changed comments to avoid encoding
+ warnings.
+
+ * Extensions/ogr/test/test_OGRShapestore.py: Changed comments to avoid
+ encoding warnings.
+
+2005-01-28 Jonathan Coles <jonathan at intevation.de>
+
+ * libraries/thuban/gdalwarp.cpp (GetImageData): Recode how the
+ mask is packed into a bit array. It's now slightly faster.
+
+2005-01-28 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/layer.py (RasterLayer.__init__): Make use_mask
+ default to true.
+
+ * Thuban/Model/load.py (SessionLoader.start_rasterlayer): Remove
+ code that loads the state of the layer's use_mask flag. Its
+ usefulness is still being debated.
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Remove
+ code that saves the state of the layer's use_mask flag. Its
+ usefulness is still being debated.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_layer): Pass
+ options to ProjectRasterFile based on the state of layer.UseMask().
+ Catch more exceptions from ProjectRasterFile so that Thuban doesn't
+ quit is there is a problem projecting.
+ (BaseRenderer.draw_raster_data): Change the documentation to
+ describe the new format (XBM) that the mask data will be in.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): The mask
+ data is in XBM format when format='RAW' which means it doesn't
+ need to be converted to a wxImage before being used as a mask
+ for a wxBitmap. Assume that if format != 'RAW' that the image
+ data and mask data are in the same format.
+
+ * libraries/thuban/gdalwarp.cpp (GetImageData): If alpha is enabled
+ and a mask is requested, convert the alpha band to a bit array in
+ XBM format. if an alpha channel is requested, simply return the
+ data in the alpha band. Provide better error handling by returning
+ python error messages (also fixes RT #2947).
+ (ProjectRasterFile): Support multiple mask options, rather than simply
+ a flag indicating that a mask should or should not be used. Provide
+ better error handling by returning python error messages.
+
+ * test/test_baserenderer.py (TestBaseRenderer.test_raster_no_projection):
+ Add mask data to test.
+
+ * test/test_layer.py (TestLayer.test_raster_layer): Test that a layer
+ should use the mask by default.
+ (TestLayerModificaton.test_raster_layer): Test that a layer should use
+ the mask by default.
+
+ * test/test_load.py (TestRasterLayer.test): Remove testing for
+ use_mask flag in file.
+
+ * test/test_save.py (SaveSessionTest.testRasterLayer): Remove testing
+ for use_mask in file.
+
+ * test/test_load_1_0_1.py: Removed. Shouldn't have been checked in.
+
+2005-01-26 Jonathan Coles <jonathan at intevation.de>
+
+ Add a new dialog box for raster layers. The dialog box allows
+ the user to toggle a mask that is generated by ProjectRasterFile
+ and is used to only draw the real parts of the projected image.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_raster_layer):
+ Instruct the warping code to generate a mask if the raster layer
+ requests one.
+ (BaseRenderer.draw_raster_data): Removed obsolete optional mask argument.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): Removed
+ obsolete optional mask argument.
+
+ * Thuban/UI/classifier.py (Classifier): Change the parent class
+ to LayerProperties and rework the code to support layout calls
+ from the parent.
+ (Classifier.dialog_layout): New. Layout the dialog box.
+ (Classifier.map_layers_removed): Removed. Moved to parent class.
+ (Classifier.map_replaced): Removed. Moved to parent class.
+ (Classifier._OnTry): Renamed to OnTry to support parent class.
+ (Classifier.OnClose): Removed. Supplied in parent class.
+ (Classifier._OnCloseBtn): Removed. Supplied in parent class as OnCloseBtn.
+ (Classifier._OnOK): Renamed to OnOK to support parent class.
+ (Classifier._OnRevert): Renamed to OnRevert to support parent class.
+
+ * Thuban/UI/layerproperties.py: New. Base class for layer properties
+ dialog boxes.
+
+ * Thuban/UI/rasterlayerproperties.py: New. Class for displaying
+ raster layer properties.
+
+ * libraries/thuban/gdalwarp.cpp: Replace the old gdalwarp.cpp code
+ with the non-simple version supplied with gdal. This allows added
+ features such as creating an alpha band.
+ (GetImageData): Generate a mask array from the alpha band that is
+ generated by gdal if the user has selected it. Try to support images
+ that have more than three bands, such as images with RGB plus an
+ alpha band.
+ (ProjectRasterFile): Convert python argument for mask and tell
+ gdal to enable or disable an alpha band.
+
+ * Thuban/Model/layer.py (BaseLayer.Type): New. Returns a string
+ describing what kind of layer the class is. Defaults to "Unknown",
+ but should be overridden by subclasses.
+ (Layer.Type): New. Override base class method.
+ (RasterLayer.__init__): Create a flag for using a mask. Record extra
+ data from gdal for display in the properties dialog.
+ (RasterLayer.Type): New. Override base class method.
+ (RasterLayer.UseMask): New. Returns True if the mask should be used.
+ (RasterLayer.SetUseMask): New. Set if the mask should be used.
+ (RasterLayer.ImageInfo): New. Return extra information about the image.
+
+ * Thuban/Model/load.py (SessionLoader.start_rasterlayer): Load
+ the mask information.
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Save mask information.
+
+ * Thuban/UI/mainwindow.py: Register the RasterLayerProperties and
+ Classifier classes as dialogs to use with the proper layer types.
+
+ * test/test_baserenderer.py (TestBaseRenderer.test_raster_no_projection):
+ Fix test.
+
+ * test/test_layer.py (TestLayer.test_raster_layer): Test new methods.
+ (TestLayerModification.build_path): New. Support function.
+ (TestLayerModification.test_raster_layer): New. Test new methods.
+
+ * test/test_save.py (SaveSessionTest.testRasterLayer): Add tests for mask.
+
+ * test/test_load.py (TestRasterLayer): Add tests for mask.
+
+ * test/test_load_1_0_1.py: New. Copied from test_load.py.
+
+ * test/test_baserenderer.py (SimpleRenderer.draw_raster_data): Removed
+ obsolete optional mask argument.
+
+2005-01-26 Nina Hüffmeyer <nhueffme at intevation.de>
+
+ * Extensions/ogr/ogrshapes.py: Added two dictionaries to ShapeStore
+ which maps the ids and the ordinals. Fixed RowIdToOrdinal(),
+ RowOrdinalToId() and ReadRowAsDict().
+
+ * Extensions/ogr/ogrstart.py: Added menu item which opens database
+ layers for existing database connections.
+
+ * Extensions/ogr/test/test_OGRShapestore.py: Fixed a message string.
+
+
+2005-01-26 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2005-01-24 Bernhard Herzog <bh at intevation.de>
+
+ Rework the status bar updates a bit to make sure the message about
+ the projections is produced at the right times.
+
+ * Thuban/UI/mainwindow.py (MainWindow.update_status_bar_messages):
+ New class variable with messages that may require a status bar
+ update.
+ (MainWindow.view_position_changed)
+ (MainWindow.update_status_bar): Rename from view_position_changed
+ to update_status_bar. It's meaning has changed now that it may
+ also generate messages about problems with projection settings.
+ (MainWindow.__init__): Use the new update_status_bar_messages
+ class variable to subscribe update_status_bar
+ (MainWindow.set_position_text): Update doc-string. This method
+ has to be renamed at some point. See doc-string and comments.
+ (MainWindow.OnClose): Unsubscribe update_status_bar from all
+ messages in update_status_bar_messages
+
+ * Thuban/UI/viewport.py (ViewPort.forwarded_map_messages): New
+ class attribute. map messages to be forwarded by the viewport.
+ (ViewPort._subscribe_map, ViewPort._unsubscribe_map): (un)subscribe
+ the messages in forwarded_map_messages
+
+2005-01-21 Bernhard Herzog <bh at intevation.de>
+
+ * test/postgissupport.py (PostGISDatabase.__init__): Tweak
+ doc-string
+ (find_postgis_sql): Update for postgis-1.0.0-rc1, which uses a
+ different name for the initialization SQL file.
+
+2005-01-21 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/baserenderer.py (proj_params_to_str): New. Takes
+ a projection and returns a formatted string representing the
+ parameters to feed to gdalwarp. This function eliminates
+ redundancy in draw_raster_layer().
+ (BaseRenderer.render_map_incrementally): Removed the optimization which
+ drew the top most raster layer first and then only those vector-
+ based layers that are above it. With the support for transparency
+ this optimization breaks correct behaviour.
+ (BaseRenderer.draw_raster_layer): Reorganize code to support possible
+ future enhancements to raster layer bounding box. The old behaviour has
+ not changed. Also, change calling parameters to draw_raster_data()
+ to specify new RAW data format and mask.
+ (BaseRenderer.draw_raster_data): Change signature to include an optional
+ parameter for mask information. Change documentation to mention
+ support for new parameter and added option for RAW data format.
+ The data argument is now a list of [width, height, data].
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_data): Add new optional
+ mask parameter. Add new condition for RAW format, which
+ significantly reduces rendering time. Add condition for
+ mask parameter.
+
+ * libraries/thuban/gdalwarp.cpp (GetImageData): New. Creates a
+ data array of RGB values from the projected image returned from
+ the gdal warping functions. In the case of palette based images, it
+ converts the NO_DATA index to the mask color.
+ (ProjectRasterFile): Removed all custom memory driver references
+ and replaced it with the standard in-memory dataset provided
+ by gdal. The return data is no longer a BMP file, but an array
+ of RGB values, one set triple per pixel.
+
+ * libraries/thuban/bmpdataset.cpp: Removed. Unnecessary.
+ * libraries/thuban/cpl_mfile.h: Removed. Unnecessary.
+ * libraries/thuban/cpl_mfile.cpp: Removed. Unnecessary.
+
+ * setup.py (thuban_build_ext.finalize_options): Removed mention
+ of cpl_mfile.cpp and bmpdataset.cpp files in the list of source
+ files. These are obsolete with the new version of gdalwarp.cpp
+
+ * test/test_baserenderer.py (SimpleRenderer.draw_raster_data):
+ Updated signature.
+ (TestBaseRenderer.test_raster_no_projection): Changed the test
+ data to be data in the uncompressed RAW format returned from
+ ProjectRasterFile.
+
+2005-01-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.view_position_changed): Made
+ string available for i18n.
+
+2005-01-20 Russell Nelson <nelson at crynwr.com>
+
+ * Resources/Projections/defaults.proj: Ruin the speling of the
+ Lambert-93 projection so it doesn't run into the wx UTF-8 bug.
+ It's the wrong thing to do in the long run, but it's necessary for
+ those users until that bug is fixed. Otherwise the projection
+ dialog segfaults. Better to annoy some Lambert-93 users with a
+ spelling mistake than every Fedora Core 3 user of Thuban-CVS.
+
+2005-01-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.view_position_changed): Added
+ docstring and comment that the warning code here is a hack.
+
+2005-01-20 Russell Nelson <nelson at crynwr.com>
+
+ * Thuban/UI/mainwindow.py (MainWindow.view_position_changed): Warn
+ user about misprojected layers when their lat/lon bounding
+ box exceeds rational lat/lon values.
+
+2005-01-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/about.py (unicodeToLocale): Improved:
+ Use 'ascii' and then 'replace' for other characters
+ when getdefaultlocale returns None. Thanks to Bernhard H. .
+
+2005-01-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.OnRetrieve): Added a comment
+ that OnRangeText might be called twice and using None as argument.
+
+2005-01-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.OnRetrieve): Add a
+ OnRangeText(0) to work around a different in wx Behaviour noticed
+ on MacOSX, thanks to Lorenzo Moretti and Daniel Calvelo for the fix.
+
+2005-01-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Thuban/UI/about.py: take iso-8859-15 when getdefaultlocale returns
+ None. (Fixes rt#2910.)
+
+2005-01-18 Frank Koormann <frank at intevation.de>
+
+ New Extension: mouseposition
+ Tool to collect mouse click positions (map coordinates) in a dialog.
+
+ * Extensions/mouseposition/__init__.py: New, extension registration
+
+ * Extensions/mouseposition/mouseposition.py: New, implements the
+ dialog and adds a tool to Thuban mainwindow.
+
+ * Extensions/mouseposition/position.xpm: New, icon for tool.
+
+2005-01-14 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2005-01-11 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.DuplicateLayer):
+ Fix indention bug.
+
+2005-01-09 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.DuplicateLayer):
+ BugFix 2901: Explicitly copy layers ClassificationColumn since it
+ is not part of the layers Classification.
+
+2005-01-03 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/renderer.py (ScreenRendererdraw_selection_incrementally):
+ BugFix 2883: Former implementation only worked on classified point
+ layers: KeyError was raised, now use the default size if field is None.
+
+2004-12-27 Bernhard Reiter <bernhard at intevation.de>
+
+ svgexport 1.0.0cvs: Fixed label export.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ class TestSVGRenderer(): New class; new test test_label_font().
+
+ * Extensions/svgexport/svgmapwriter.py
+ (SVGRenderer.label_font()): initialised Font size with self.factor now,
+ makes test_label_font happy.
+
+ * Extensions/svgexport/TODO: crossed out fixed label export item.
+ Added item for options.
+
+ * Extensions/svgexport/__init__.py: Bumped version to 1.0.0cvs.
+
+2004-12-27 Russell Nelson <nelson at crynwr.com>
+
+ Middle mouse button pans.
+
+ * Thuban/UI/view.py (MapCanvas.__init__): Subscribe also
+ OnMiddleDown and OnMiddleUp events.
+ (MapCanvas.OnMiddleDown): New. Activate the pan tool and remember the
+ previously used tool.
+ (MapCanvas.OnMiddleUp): New. Reactivate the remebered tool used before
+ pressing the middle mouse button.
+
+2004-12-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: More translations.
+
+2004-12-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.load_user_proj): Added a
+ \n to stderr after the warnings. Thanks to Russell Nelson.
+
+2004-12-20 Nina Hueffmeyer <nhueffme at intevation.de>
+
+ * Extensions/ogr/ogrshapes.py: Fixed some issues from
+ Bernhard (coding guidelines etc.). Additionally it is now possible to
+ display shapefiles containing feature collections (e.g.polygons
+ with holes). Works with gdal 1.2.1 now.
+
+ * Extensions/ogr/test/test_OGRShapestore.py: Fixed some issues
+ from Bernhard (coding guidelines etc.). If ogr can't be imported,
+ tests are skipped now.
+
+ * Extensions/ogr/ogrstart.py: Fixed some typings.
+
+2004-12-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/TODO: updated to add support for
+ raster layers and labels for 1.0.1.
+
+ * Extensions/svgexport/svgmapwriter.py (draw_raster_layer):
+ Issue a warning now.
+
+2004-12-19 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/TODO: Added idea to support triggering
+ the application down the pipe.
+
+2004-12-19 Bernhard Reiter <bernhard at intevation.de>
+
+ svgexport: Improved code quality, mainly by better naming.
+
+ * Extensions/svgexport/svgmapwriter.py:
+ DrawPath() renamed to DrawPolygonPath(),
+ added documentation, improved comments and variable names.
+
+ * Extensions/svgexport/svgmapwriter.py,
+ Extensions/svgexport/test/test_svgmapwriter.py:
+ All using DrawPolygonPath() now, the default parameter closed=True
+ omitted.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ renamed test_polygon_opened() to test_polyline()
+ renamed test_transparent_polygon() to test_transparent_polyline()
+
+2004-12-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ Some fixes of gns2shp extension.
+
+ * Extensions/gns2shp/test/__init__.py: New. Make this directory a
+ package.
+
+ * Extensions/gns2shp/test/test_gns2shp.py: Add some import paths
+ dynamically.
+
+ * Extensions/gns2shp/test/README: Simplified description how to test.
+
+ * Extensions/gns2shp/gns2shp.py (gns2shp): Fixed doc-string,
+ fixed some dimensions of fields according to the GNS documentation
+ which seems to change undocumented.
+ Now killing trailing \n and/or \r from MODIFY_DATE.
+ This fixes RT#2453.
+
+2004-12-18 Bernhard Reiter <bernhard at intevation.de>
+
+ svgexport 1.0.0: Treats holes and islands nicely. Documentation added.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Added new tests: test_export_polygon_with_hole()
+ and test_polygon_with_hole().
+
+ * Extensions/svgexport/svgmapwriter.py
+ (draw_polygon_shape()): Uses DrawPath correctly now.
+
+ * Doc/manual/thuban-manual.xml: Added documentation for stable
+ extention svgexport.
+ * Doc/manual/thuban-manual-de.xml: Copied English section about
+ svexport over.
+
+ * Extensions/svgexport/__init__.py: Bumped version number to 1.0.0.
+
+ * Extensions/svgexport/svgsaver.py,maplegend.py:
+ Moved from experimental to stable extension menu.
+
+ * Extensions/svgexport/TODO: updated.
+
+
+2004-12-18 Bernhard Reiter <bernhard at intevation.de>
+
+ Added Extensions/svgexport/TODO
+
+2004-12-18 Bernhard Reiter <bernhard at intevation.de>
+
+ Refactored in svgexport:
+ DrawPath replaces DrawPolygon; added newline in front of "M" in paths.
+
+ * Extensions/svgexport/svgmapwriter.py
+ Added verbosity level 3 to print out polygon points.
+ (class Point): added __repr__
+ (class Brush, __str__()): Added space after ,.
+ (DrawPolygon): Renamed to DrawPath()
+ (DrawPath): Takes list of polygons as input now, adds \n before "M"s.
+ (DrawLines): Using DrawPath now.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Replaced DrawPolygon() calls with DrawPath() and put the first argument
+ inside another list. Adapted test data with a newline before "M".
+
+2004-12-18 Bernhard Reiter <bernhard at intevation.de>
+
+ Refactored svgexport tests: 9 double tests runs eliminated;
+ code size reduced by 8 lines.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ (class TestWithDC): Renamed to BaseTestWithDC, moved to top.
+ (class BaseWithDCtools): New, subclass from BaseTestWithDC.
+ (class TestDrawSplines): now subclass from BaseTestWithDCtools,
+ this fixed the double running of the nine tests of TestVirtualDC.
+ (class TestVirtualDC): Using self.dc and self.file from setUp().
+
+2004-12-17 Bernhard Herzog <bh at intevation.de>
+
+ Two windows specific fixes ported from thuban-10-branch:
+
+ * Thuban/UI/about.py (unicodeToLocale): Use getdefaultlocale
+ instead of getlocale because getlocale doesn't return a usable
+ encoding name on a german windows 2000
+
+ * setup.py: windows build: Removed the absolute path names and
+ made all prfixes relative to the directory containing setup.py.
+ Makes it a little easier to adapt to a different system.
+
+2004-12-16 Bernhard Herzog <bh at intevation.de>
+
+ Add support for PostGIS tables with LINESTRING geometries.
+ Fixes RT#2299
+
+ * Thuban/Model/postgisdb.py (shapetype_map): Add LINESTRING
+
+ * test/postgissupport.py
+ (PostgreSQLServer.get_default_static_data_db): Rename the "roads"
+ table to "roads-multi" because it now uses MULTILINESTRING
+ geometries and introduce a new "roads" table that uses LINESTRING
+ (coords_to_multilinestring): Make the doc string more precise
+ (coords_to_linestring): New. Create a LINESTRING WKT
+ representatin
+ (wkt_converter): Add coords_to_linestring
+ (upload_shapefile): Rephrase the doc-string a bit.
+
+ * test/test_postgis_db.py (TestPostGISShapestoreArc)
+ (LineStringTests)
+ (TestPostGISShapestoreLineString)
+ (TestPostGISShapestoreMultiLineString): Split
+ TestPostGISShapestoreArc into a base class LineStringTests and two
+ derived classes TestPostGISShapestoreLineString for LINESTRING
+ geometries and TestPostGISShapestoreMultiLineString for
+ MULTILINESTRING geometries. Most test methods are in the base
+ class with the exception of tests that explicitly check the raw
+ format.
+
+2004-12-16 Bernhard Herzog <bh at intevation.de>
+
+ Make the test suite work with PostGIS 0.8.2 and PostgreSQL 7.4
+
+ * test/postgissupport.py (find_postgis_sql): Different postgis
+ versions put the postgis.sql file into slightly different places
+ so we have to look in both. The updated doc string describes this
+ is more detail.
+
+ * test/test_postgis_db.py
+ (TestPostGISSpecialCases.test_column_name_quoting): The return
+ value of UniqueValues is unsorted, so it has to be sorted for
+ comparison.
+
+2004-12-16 Bernhard Herzog <bh at intevation.de>
+
+ Fix for RT#2237
+
+ * Thuban/UI/projdialog.py (ProjFrame._show_proj_panel): If the
+ panel to be shown is the UnknownProjPanel disable the OK and Try
+ buttons. Otherwise enable them.
+ (ProjFrame.__GetProjection): The UnknownProjPanel returns None for
+ the parameters. In that case __GetProjection also returns None
+ now.
+
+2004-12-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.__init__): Set the
+ minimum number of classes to 2. The calculate_quantiles needs at
+ least two and raises an exception otherwise.
+ Fixes RT#2549
+
+2004-12-15 Bernhard Herzog <bh at intevation.de>
+
+ * test/postgissupport.py (PostgreSQLServer.execute_sql): Extend to
+ so that it returns a result for select statements.
+ (PostgreSQLServer.server_version): New. Return the version of the
+ server software.
+ (PostgreSQLServer.require_authentication): The format of
+ pg_hba.conf has changed between PostgrSQL 7.2 and 7.3. Check the
+ server version and generate the file in the correct format
+
+2004-12-15 Bernhard Herzog <bh at intevation.de>
+
+ * test/postgissupport.py (PostgreSQLServer.is_running): Fix typo
+ in the doc string and rephrase it a little.
+
+2004-12-15 Frank Koormann <frank at intevation.de>
+
+ * test/test_load.py (TestAltPath.checkSession): New, extended checks if
+ session has been loaded successfully. The check is called by the relevant
+ tests after executing load_session().
+
+2004-12-13 Bernhard Herzog <bh at intevation.de>
+
+ Make sure the region used to determine which shapes are visible
+ actually matches the region on the printed page. If this isn't
+ done properly some shapes might not be printed.
+ Fixes RT #2692
+
+ * Thuban/UI/view.py (MapPrintout.draw_on_dc): The region for the
+ renderer has to be at the same position as the mapregion
+
+ * Thuban/UI/renderer.py (ExportRenderer.RenderMap): self.region
+ has to be moved by (self.shiftx, self.shifty) too.
+
+2004-12-13 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/pyprojection/Projection.i: Work around a bug in the
+ generated python code which leads to exception in the __del__
+ method when the constructor fails. See the comments in the code
+ for more details.
+
+ * libraries/pyprojection/Projection.py: Updated from Projection.i
+ with SWIG.
+
+2004-12-13 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_load.py (TestAltPath.test_01_single_path_error_fix)
+ (TestAltPath.test_02_path_error_fix_from_list)
+ (TestAltPath.test_05_path_error_fix_from_list_changed)
+ (TestAltPath.test_06_path_error_fix_from_list_fails): self.session
+ is destroyed in tearDown, so there's no need to do it in a test
+ case.
+
+ * Thuban/Model/load.py (SessionLoader.open_shapefile): Remove a
+ debug print
+
+2004-12-13 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py
+ (TestDrawSplines.setUp): Do not use super with the unittest
+ classes because in Python 2.2 they're still old-style classes.
+
+2004-12-13 Frank Koormann <frank at intevation.de>
+
+ Alternative Path feature: When loading a (moved) session where
+ shapefiles cannot be found, ask the user. Use the specified path
+ if further shapefiles are missing. However, ask the usr for confirmation
+ in such cases.
+
+ * test/test_load.py (TestAltPath): New, tests for alternative path feature
+ in load_session()
+ (Shapefile_CallBack): Helper, implements controllable callback.
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit):
+ Added "alt_path" to self.path
+ (ThubanApplication.OpenSession): Added shapefile_callback as second
+ callback similar to db_connection_callback.
+ (ThubanApplication.run_alt_path_dialog): New, implementaion of
+ shapefile_callback. In addition to raising the dialog the control of
+ self.path('alt_path') is implemented here.
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Added shapefile_callback.
+ (SessionLoader.open_shapefile): Open shapefile, eventually with
+ alternative path. This wrapps the "theSession.OpenShapefile(filename)"
+ formerly used in start_fileshapesource()/start_layer().
+ (SessionLoader.start_fileshapesource): Call open_shapefile().
+ (SessionLoader.start_layer): Call open_shapefile().
+ (load_session): Added shapefile_callback.
+
+ * Thuban/UI/altpathdialog.py: New, implements dialogs for alternative path
+ feature (search / check).
+
+ * Doc/manual/thuban-manual.xml: Added documentation of new feature.
+
+2004-12-11 Bernhard Reiter <bernhard at intevation.de>
+
+ svgexport 0.9.2: Point size supports for maps.
+
+ * Extensions/svgexport/svgmapwriter.py: Added import of SHAPETYPE_POINT
+ (def draw_point_shape): new parameter size defaults to 2 as before.
+ (draw_shape_layer_incrementally): Moved draw_func log line higher.
+ Added draw_func call with size when dealing with a point layer.
+
+ * Extensions/svgexport/__init__.py: bumped version to 0.9.2.
+
+2004-12-11 Bernhard Reiter <bernhard at intevation.de>
+
+ Made sure that newlines are inserted in the svg path d attributes
+ to raise the chance that the line length will be below 255 characters,
+ as recommended by REC SVG 1.1 in section 8.3.1.
+
+ * Extensions/svgexport/svgmapwriter.py(DrawPolygon):
+ Adding \n before L's and changed whitespace handling.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Adapted tests to new whitespace handling of DrawPolygon.
+
+2004-12-11 Bernhard Reiter <bernhard at intevation.de>
+
+ * Doc/technotes/coding_guidelines.txt: easy typo fixed.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Removed test_drawbezier in favour of new test_drawspline3 and
+ test_drawspline4 within new class TestDrawSplines(TestVirtualDC).
+ All only to test DrawSpline.
+
+ * Extensions/svgexport/svgmapwriter.py(DrawSpline):
+ New implementation now really using the strange algorithm of
+ xfig 3.1's approximated splines and its conversion to postscript
+ with one twist: SVG can do quadratic beziers, so skipped translation
+ to cubic beziers.
+ (TestWithDC): Typo in comment fixed.
+
+2004-12-09 Martin Schulze <joey at infodrom.org>
+
+ * Thuban/Model/classgen.py: Added missing character encoding
+
+ * Extensions/wms/properties.py (OpenWMSProperties): removed
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.error): Dropped
+ support for get_srs_discrepancies() since there are no
+ discrepancies anymore (was a thinko)
+
+ * Extensions/wms/layer.py (WMSLayer.GetMapImg): Improved graphic
+ format priority now that more formats are supported globally by
+ the render engine.
+
+2004-12-08 Silke Reimer <silke at intevation.de>
+ * Extensions/ogr/ogrshapes.py: Substituted ogr-method CloseRings
+ because it is not available in all versions of ogr
+
+2004-12-08 Bernhard Reiter <bernhard at intevation.de>
+ * Extensions/ogr/__init__.py: Added empty __init__.py to heal
+ global tests until a real one is commited.
+
+2004-12-07 Nina Hüffmeyer <nhueffme at intevation.de>
+
+ * /Extensions/ogr/: Adding a new extension to read shapefiles with
+ ogr. It is planned to add other vector formats.
+
+ * /test/runtests.py: Adding tests from /Extensions/ogr/test/.
+
+2004-12-07 Jan-Oliver Wagner <jan at intevation.de>
+
+ * /Extensions/svgexport/test/test_svgmapwriter.py: Reverting
+ part of a (non-)fix to renable that the tests are always
+ executed.
+
+2004-12-07 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Added test_drawbezier() to test DrawSpline().
+
+ * Extensions/svgexport/svgmapwriter.py(DrawSpline):
+ Really implemented bezier drawing.
+
+ * Extensions/svgexport/__init__.py: Bumped version of svgexport
+ to 0.9.1 because now the legend examples lines styles
+ will be drawing with beziers.
+
+2004-12-05 Martin Schulze <joey at infodrom.org>
+
+ * Thuban/UI/renderer.py (raster_format_map): Added PNG, TIFF and
+ GIF as supported bitmap image formats (helpful for the WMS extension)
+
+2004-11-30 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_ogclib.py (TestOGCLib.test_compareURLs):
+ Improved the test for the internal compare method
+
+2004-11-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Added
+ Norbert Solymosi for hungarian translation and Ole Rahn
+ as contributor. Moved Bernhard Reiter from Contributor
+ to Developer.
+
+2004-11-27 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Removed Jan from author list as he did not change enough significant
+ lines yet.
+
+ * Extensions/svgexport/__init__.py: Added Bernhard as author
+ of the Extension.
+
+2004-11-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * po/hu.po: New. Hungarian translation. Contributed
+ by Norbert Solymosi.
+
+2004-11-26 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py
+ (Testobjectexport.test_transparent_polygon): Commented out some
+ debug prints
+
+2004-11-24 Jan-Oliver Wagner <jan at intevation.de>
+
+ Fix broken tests for svg extension and added svg legend
+ to Experimental menu.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py: Fix to have
+ the test run correctly even if the extension is a package.
+ Also removed the "import Thuban" which makes no sense.
+
+ * Extensions/svgexport/__init__.py: Fix to have the extensions'
+ test module also be executed from the global test routine.
+ This is done by looking for the absense of the DISPLAY variable.
+
+ * Extensions/svgexport/maplegend.py: Moved the menu entry from Extensions
+ to Experimental menu since this module has yet not reached a stable
+ status (ie. 1.0).
+
+2004-11-22 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/svgmapwriter.py:
+ Added verbose variable and some logging depending on it.
+ (class VirtualDC(XMLWriter)): Minor improvement in the polygon loop,
+ because counting i is not necessary.
+ (class Pen, class Brush): Added simple __str__ methods.
+ (SVGRenderer.draw_polygone_shape): Fix #2698 (transparent polygons are
+ not exported to svg file) Note: holes still unhandled.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Made a baseclass TestWithDC for test needed a DC.
+ Added tests for bug #2698 (transparent polygons are not
+ exported to svg file):
+ Testobjectexport.test_transparent_polygon()
+
+ * Thuban/Model/base.py (UnsetModified):
+ Fixed some typos in docstring.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_polygon_shape()):
+ Added hints on the used algorithm for handling holes.
+
+2004-11-20 Jan-Oliver Wagner <jan at intevation.de>
+
+ Some face lifting for the examples.
+
+ * Examples/__init__.py: Make this directory a package.
+
+ * Examples/simple_extensions/__init__.py: Make this directory a package.
+
+ * Examples/simple_extensions/hello_world.py: Moved entry from Extensions
+ menu to Examples menu.
+
+ * Examples/simple_extensions/simple_command.py: Some more comments,
+ minor changes.
+
+ * Examples/simple_extensions/simple_tool.py: Minor changes.
+
+2004-11-20 Jan-Oliver Wagner <jan at intevation.de>
+
+ Changed way of extension registry for wms and added extension
+ registry for umn_mapserver extension.
+
+ * Extensions/wms/__init__.py: Added registry entry and the importing
+ of the actual wms module. Included a test for the required PyOGCLib.
+
+ * Extensions/wms/wms.py: Removed registry entry (moved to __init__.py).
+
+ * Extensions/umn_mapserver/__init__.py: Added registry entry and the
+ importing of the actual umn mapserver management modules.
+ Included a test for the required Python MapScript.
+
+2004-11-20 Jan-Oliver Wagner <jan at intevation.de>
+
+ Changed way of extension registry for importAPR, bboxdump
+ and added extension registry for svgexport.extension registry for
+ svgexport.
+
+ * Extensions/importAPR/__init__.py: Added registry entry and the importing
+ of the actual importAPR module.
+
+ * Extensions/importAPR/importAPR.py: Removed registry entry (moved to
+ __init__.py).
+
+ * Extensions/bboxdump/__init__.py: Added registry entry and the importing
+ »···of the actual bboxdump module.
+
+ * Extensions/bboxdump/bboxdump.py: Removed registry entry (moved to
+ »···__init__.py).
+
+ * Extensions/svgexport/__init__.py: Added registry entry and the importing
+ of the svgsaver module.
+
+ * Extensions/svgexport/svgsaver.py: Moved the menu entry from Extensions
+ to Experimental menu since this module has yet not reached a stable
+ status (ie. 1.0).
+
+2004-11-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ Now the hit test considers the size of point symbols.
+
+ * Thuban/UI/viewport.py (ViewPort._hit_point): Added optional parameter
+ 'size' defaulting to the previously fixed value 5.
+ Extended doc-string.
+ (Viewport._find_shape_in_layer): Resolved FIXME regarding flexibility
+ for symbols.
+ Now the size of the largest point symbol is determined to find out
+ about whether the point has been hit.
+ This fixes the problem that only clicks inside a fixed distance of
+ 5 where found.
+
+2004-11-17 Jan-Oliver Wagner <jan at intevation.de>
+
+ Another open issue fixed regarding sizeable symbols: correct rendering of
+ selected symbols.
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_selection_incrementally):
+ Added consideration of the specific size of point symbols.
+ The property for each point symbol is retrieved and the size applied
+ for the rendering method.
+ Added doc-string.
+
+2004-11-16 Jan-Oliver Wagner <jan at intevation.de>
+
+ Changed way of Extension Registry for gns2shp and profiling.
+
+ * Extensions/gns2shp/gns2shp.py: Removed registry entry (moved to
+ __init__.py).
+
+ * Extensions/gns2shp/__init__.py: Added registry entry and the importing
+ of the actual gns2shp module.
+
+ * Extensions/profiling/profiling.py: Removed registry entry (moved to
+ __init__.py).
+
+ * Extensions/profiling/__init__.py: Added registry entry and the importing
+ of the actual profiling module.
+
+2004-10-28 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/: Minor improvements to doc strings.
+
+2004-10-07 Jan-Oliver Wagner <jan at intevation.de>
+
+ Further elements for sizable point objects now
+ making this feature usable though not yet complete.
+
+ * Thuban/Model/save.py (SessionSaver.write_classification): Write
+ attribute 'size' for cldata when the shape layer is of point type.
+ This also now make the test_load.py tests happy.
+
+ * Thuban/Model/classgen.py (CustomRamp.GetProperties): Added size
+ gradient.
+
+ * Thuban/UI/classifier.py (ID_SELPROP_SPINCTRL): Renamed to
+ ID_SELPROP_SPINCTRL_LINEWIDTH.
+ (ID_SELPROP_SPINCTRL_LINEWIDTH): New Id replaces ID_SELPROP_SPINCTRL.
+ (ID_SELPROP_SPINCTRL_SIZE): New Id.
+ (SelectPropertiesDialog.__init__): Added a second spin control
+ for the size in case the corresponding layer is of point type.
+ (SelectPropertiesDialog._OnSpin): Renamed to _OnSpinLineWidth.
+ (SelectPropertiesDialog._OnSpinLineWidth): New. Former _OnSpin.
+ (SelectPropertiesDialog._OnSpinSize): New. Set size of property
+ and refresh preview.
+
+
+
+2004-10-04 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_parser.py
+ (TestWMSCapabilitiesParser.test_compareLists): Added missing
+ self-test for compareLists()
+ (TestWMSCapabilitiesParser.test_compareDicts): Added missing
+ self-test for compareDicts()
+ (TestWMSCapabilitiesParser.test_compareLists): Adding more tests
+ to verify the test routine fails with non-equal arguments
+ (TestWMSCapabilitiesParser.test_compareDicts): Adding more tests
+ to verify the test routine fails with non-equal arguments
+
+2004-10-03 Jan-Oliver Wagner <jan at intevation.de>
+
+ First elements for sizeable point objects.
+
+ * Resources/XML/thuban-1.1.dtd: Added size attribute to cldata.
+
+ * Data/iceland_sample_size.thuban: New. Sample for sized point objects.
+
+ * test/test_load.py (ClassificationTest.TestLayers): Added SetSize in case
+ of a corresponding argument is given.
+ (TestSymbolSize): New. Test the size attribute of cldata.
+
+ * Thuban/Model/classification.py: Removed some trailing whitespaces.
+ (ClassGroupProperties.__init__): Set default size.
+ (ClassGroupProperties.SetProperties): Set the size.
+ (ClassGroupProperties.GetSize): New. Return the size.
+ (ClassGroupProperties.SetSize): New. Set the size.
+ (ClassGroupProperties__eq__): Compare also size.
+ (ClassGroupProperties__repr__): Print also size.
+
+ * Thuban/Model/load.py (SessionLoader.start_cldata): Also parse
+ the size attribute.
+
+ * Thuban/UI/classifier.py (ClassDataPreviewer.Draw): Added doc-string.
+ Also, now there is a return value that indicates whether the drawing
+ size exceeded the given rect extent and if so the new extent.
+ Finally, point objects are drawn depending on the size. If either
+ the width or height is exceeded, the new extent is returned.
+ (ClassRenderer.Draw): Now when calling the previewer drawing function,
+ evaluate the return value and, if not None, adapt the grid widget size
+ accordingly and redraw again.
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_shape_layer_incrementally):
+ If the draw function is for points, call it with the size as additional
+ parameter.
+ (BaseRenderer.draw_point_shape): Added additional, optional parameter for
+ the size. Compute the radius using the size.
+
+ * Extensions/importAPR/apr.py (APR_BMkSym.GetThubanProp): Now
+ that Thuban supports size, apply this correctly.
+
+ * Extensions/importAPR/importAPR.py: Bumped version to 0.1.1.
+
+2004-10-03 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml: Started translation of
+ Map chapter.
+
+2004-10-01 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/properties.py (wmsProperties.__init__): Extended
+ argument for general use through properties-dialog selector
+
+ * Thuban/UI/classifier.py: Register properties dialog classes for
+ both provided layer classes/types.
+
+ * Thuban/UI/mainwindow.py (MainWindow.OpenLayerProperties): The
+ map can be retrieved through the parent which is passed to the
+ constructor anyway and doesn't require an argument of its own,
+ required for the unification of arguments for general use through
+ properties-dialog selector.
+ (MainWindow.OpenOrRaiseDialog): Move the logic for checking
+ whether a dialog is already opened (and raising it to the users
+ attention) and creating a new dialog into a function of its own
+ (MainWindow.OpenLayerProperties): Use the new OpenOrRaiseDialog()
+ method
+ (MainWindow.OpenLayerProperties): Utilise the new ClassMapper for
+ global registration of properties dialog classes (which are indeed
+ layer-specific).
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Unify arguments
+ for general use through properties-dialog selector, the map can be
+ retrieved through the parent and doesn't require an argument of
+ its own.
+
+ * Extensions/wms/wms.py: Register the properties dialog class for
+ the provided WMS layer
+
+2004-09-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ New feature: Registry for Extensions.
+
+ * Thuban/UI/extensionregistry.py: This module defines a registry for
+ Extensions.
+
+ * Thuban/UI/about.py (About.__init__): Added description
+ of the registered extensions with all of the information.
+
+ * Thuban/Model/extension.py (Extension): Improved doc-string.
+
+ * Extensions/gns2shp/gns2shp.py, Extensions/importAPR/importAPR.py,
+ Extensions/bboxdump/bboxdump.py, Extensions/profiling/profiling.py,
+ Extensions/wms/wms.py: Added registration of the extension.
+
+2004-09-27 Bernhard Reiter <bernhard at intevation.de>
+
+ More fixes to svgexport to make used ids unique and
+ conforming to XML's Name production.
+
+ * Extensions/svgexport/test/test_svgmapwriter.py: Added new tests
+ test_xml_id_constraints(), test_make_ide_nosetbaseid() and
+ test_make_id_nonintegersetid(). Switched SetID and SetBaseID.
+ Added Bernhard R. as author.
+ * Extensions/svgexport/svgmapwriter.py (make_id): Using "_" as
+ concatenation char now (makes test_make_ide_nosetbaseid() valid).
+ Also transform second id part with "%d" and catch the TypeError
+ to raise SVGMapWriterError (making test_make_id_nonintegersetid() ok).
+ Corrected typo inBernhard's author line.
+ (SetBaseID): Return the transformed base id. Transform characters
+ which are not alnum() or in ".-_" to binascii.b2a_hex(). Added
+ import binascii. If to be set string starts with "xml" or so, add "t".
+ (draw_shape_layer_incrementally): use the returned value of SetBaseID
+ for used_baseids checks.
+
+2004-09-25 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_layer.py (TestLayer.test_arc_layer_with_projection):
+ Remove a debug print and some tab characters.
+
+2004-09-25 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/svgmapwriter.py: Added Bernhard R. as Author.
+ (SetBaseID, SetID, make_id): Improved docstring comments to explain
+ the interaction of the three functions and the XML id contrains.
+
+
+2004-09-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/ThubanModel.xmi: New. UML file for Thuban Model
+ Module.
+
+ * Doc/README: Added info on ThubanModel.xmi.
+
+2004-09-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/README: New. Some info about how to generate technical
+ documentation from the source code.
+ This text was send to the Thuban developer mailing list on
+ September 21st 2004 by Bernhard Reiter.
+
+2004-09-21 Bernhard Reiter <bernhard at intevation.de>
+
+ Improved the svgexport to only use unique ids. Will issues
+ an error message dialoge when two layer names are the same.
+ ShapeIDs are now added with a dash within the svg ids.
+
+ * Extensions/svgexport/svgmapwriter.py (SVGMapWriterError): New.
+ * Extensions/svgexport/test/test_svgmapwriter.py: Added imports
+ (TestSVGRenderer): New test class with test_make_in() and
+ test_check_for_layer_name_clash()
+ * Extensions/svgexport/svgmapwriter.py (SVGRenderer): Fixed __init__()
+ and draw_shape_layer_incrementally() to not use a baseid twice,
+ satisfying test_check_for_layer_name_clash()
+ (VirtualDC.make_id): Use a dash between baseit and id, satisfies
+ test_make_in().
+ * Extensions/svexport/svgsaver.py: Import SVGMapWriterError, wxOK
+ and wxICON_HAND.
+ (write_to_svg): Put dc and rendering in a try statement and on
+ catching SVGmapWriterError notify the user and delete the target file.
+
+2004-09-20 Bernhard Reiter <bernhard at intevation.de>
+
+ * Model/base.by, Model/layer.py: Fixed typos in docstrings.
+
+2004-09-03 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile(MF_Class.add_thubanstyle): Fix a
+ small bug with the line color. Now the line color will now only set
+ if it is set in Thuban an not Transparent.
+
+ * Extensions/umn_mapserver/mf_export(tblayer_to_map): Fixed a bug with
+ deleting the layers from mapfile. Now all layers will delete backwards
+ from the last.
+
+2004-08-20 Silke Reimer <silke at intevation.de>
+
+ * Thuban/Model/layer.py:
+ Fixes bug in projection handling: Otherwise very large region might not
+ have valid values in the layer's projection.
+
+2004-08-20 Silke Reimer <silke at intevation.de>
+
+ * Thuban/UI/about.py:
+ small changes to be consistent with coding style.
+
+2004-08-13 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_ogclib.py (TestOGCLib.compare_URLs):
+ Adjusted a comment
+
+2004-08-11 Silke Reimer <silke at intevation.de>
+
+ * Thuban/UI/about.py: Small changes to encoding related stuff to avoid
+ too many and too enhanced imports of locale
+
+2004-08-10 Silke Reimer <silke at intevation.de>
+
+ * Thuban/UI/about.py: Fixed encoding problem of about dialog: Added
+ function unicodeToLocale() to convert special characters to users
+ locale encoding
+
+2004-08-10 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/technotes/coding_guidelines.txt: Added rule 'Method names start with
+ lower case letter'
+
+2004-08-09 Jan Schüngel <jschuengel at intevation.de>
+
+ * ChangeLog: Rewrite the last ChangeLog entry to follow
+ the standard way.
+
+ * Extensions/umn_mapserver/mapfile: Moved the import AnnotationLayer to
+ the function where it is needed, because it don't works if it stands
+ at the beginning.
+ (MF_Layer.__init__): Removed the extra numclassed variable. Now
+ numclasses from the mapscript will be used.
+ (MF_Layer.get_index): New. Return the index of the layer in mapfile.
+ (MF_Layer.set_classes): New. A Classlist will be set to the layer.
+ (MF_Layer.set_metadata): New. A Metadata mapscript object will set.
+ (MF_Layer.remove_allclasses): New. All class of the layer will remove.
+ (MF_Map.create_new_layer): New. A new Layer is created and associated
+ with the mapscript object.
+ (MF_Map.set_layerorder): New. The Layer order like in thuban is set in
+ the mapscript.
+ (MF_Map.add_thubanlayer): Now a new layerobj is created if no one is
+ linked to the layer in thuban, else the layerobject linked to the
+ thubanlayer will be used.
+ AnnotationLayer will now store the filename of the shapefile.
+ (MF_Map.remove_layer): If a layer is removed the associated object
+ must be set new.
+
+ * Extensions/umn_mapserver/mf_export.py(tb_layer_to_map): Add all
+ layers which are exists in thuban to the mapobj. All removed Layers
+ will be removed from the mapobj.
+ Added comments to all functions.
+ (thuban_to_map): No layer will be removed here.
+
+ * Extensions/umn_mapserver/mf_handle.py
+ (_has_umn_mapobj_and_selectedlayer): Activating the layer menu. Now
+ Layersettings for the mapserver kann be edited.
+
+ * Extensions/umn_mapserver/mf_import.py: Now all layers which are
+ imported, will be linked with the associated MF_Layer.
+ (import_mapfile): All layers, which are not selected, will be removed.
+ Disable the "import layer from mapfile" menu option.
+
+ * Extensions/umn_mapserver/sample/iceland.map: Set the status of the
+ Annotation Layer from DEFAULT to OFF. The DEFAULT setting turns the
+ layer on permanently.
+
+2004-08-03 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py(MF_Metadata.remove_allmetadata):
+ New. This function removes all metadata
+ (MF_Layer.set_group): New. Set the group setting.
+ (MF_Layer.get_group): New. Get the group setting.
+ (MF_Map): Removed the extra numlayers variable, used the mapscript
+ parameter instead.
+ (MF_Map.get_numlayers): New. This get numlayers.
+ (MF_Map.remove_all_layers): New. Removes all layers from the mapobj.
+ (MF_Map.add_thubanlayer): Replaced the exception handling by a check
+ if the object is an instance. Also added the annotation layer here to
+ export, but only the layer is created in the mapfile.
+
+ * Extensions/umn_mapserver/mf_export.py(export_mapfile): Removed
+ the check if a mapobj exist, because its not needed anymore. The
+ export function is only available if a mapobj exist.
+ Use the new function to remove all layers.
+
+ * Extensions/umn_mapserver/mf_handle.py(Layer_Dialog): Added a group
+ option and the metadata button. The layer dialog is temporary disabled.
+ (Metadata_CustomDataTable): Added some functions to show the grid
+ correct.
+
+ * Extensions/umn_mapserver/mf_import.py: Moved the code for showing
+ the number of layer from import_mapfile to this function.
+ (AnnotationLayer): New. This Class shows the Annotation layer in
+ thuban. The layer don't do anything. It's only to show the layer
+ and to save the layer order.
+ (add_annotationlayer): New. Import an annotation layer to thuban.
+ (select_layer2import): New. Import only layers to thuban and not
+ the other settings like projection or scalebar.
+ (create_new_mapfile): Moved the _has_umn_mapobj function and the
+ create_new_mapfile functions from mf_handle.py to mf_import.py.
+
+ * Extensions/umn_mapserver/sample/iceland.map: Added the group
+ parameter to the roads and cultural layers. Also added a new
+ Annotation Layer for the cultural points.
+
+ * Extensions/umn_mapserver/sample/iceland.html: Added the select
+ option for the annotation layer.
+
+ * Extensions/umn_mapserver/sample/index.html: Added the start
+ parameter for the annotation layer.
+
+2004-08-01 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual-de.xml (Chapter Session Management):
+ translation completed.
+
+ * Doc/manual/thuban-manual.xml (Chapter Session Management):
+ Fixed unprecise description for Save Session.
+
+2004-07-31 Jan-Oliver Wagner <jan at intevation.de>
+
+ Started translation of Users Manual into german.
+
+ * Doc/manual/thuban-manual-de.xml: New. German Users Manual.
+
+ * Doc/manual/Makefile: Added build instructions for german
+ users manual.
+
+ * Doc/manual/thuban-manual.xml: Minor corrections in Introduction.
+
+2004-07-28 Jan Schüngel <jschuengely at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py(MF_Metadata): Changed all class
+ functions. Now all metadata will handle by the function and its not
+ needed to initialize it from outside. Therefor the associated mapobj
+ will be stored in the Metadata Object. So we can use the special
+ functions from the associated mapobj to get the Metadata.
+ Therefor all initialization code for the metadata is removed from the
+ other classes.
+ (MF_Layer): Added a function to get the metadata object.
+ (MF_Map): Added a function to set the mappath, the path where
+ the mapfile ist stored.
+
+ * Extensions/umn_mapserver/mf_export.py(thuban_to_map): Changed the code
+ to set the extent in the mapfile. Now the code is set by the displayed
+ data in the Thuban-view.
+ (export_mapfile): The shapepath is now set empty, until relative
+ pathnames are supported.
+
+ * Extension/umn_mapserver/mf_handle.py: Added a dialog to handle
+ metadata. Yet only mapfile metadata are supported. Layer and class
+ supported are not implemented.
+ Added a dialog to handle layer informations. The dialog only shows the
+ selected layer at the moment.
+
+ * Extensions/umn_mapserver/mf_import.py(import_mapfile): Changed the
+ code for setting the extent in thuban. Now the extent is set to the
+ given extent from the mapfile.
+ Fixed a logical mistake. Now the extent is set when realy a layer is
+ loaded, and not if one is selected to load.
+
+ * Extensions/umn_mapserver/sample/iceland.html: Added code to zoom and
+ move the shown map in the browser.
+
+ * Extensions/umn_mapserver/sample/iceland.map: Added a new metadata
+ line to the mapobj and added metadata to the political layer.
+
+ * Extensions/umn_mapserver/test/test_mapserver.py: Changed the test
+ for Metadata.
+
+2004-07-26 Martin Schulze <joey at infodrom.org>
+
+ * Thuban/Lib/classmapper.py (ClassMapper.has): Added the new
+ ClassMapper
+
+ * test/test_classmapper.py (TestMapping.test_mapper): Added a Test
+ case for the new ClassMapper
+
+
+2004-07-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/viewport.py (ViewPort.VisibleExtent): New. Return the
+ visible extent of the map in projected coordinates
+
+ * test/test_viewport.py (SimpleViewPortTest.test_default_size)
+ (SimpleViewPortTest.test_init_with_size): Add some VisibleExtent()
+ tests.
+ (SimpleViewPortTest.test_visible_extent): New. The real test for
+ VisibleExtent()
+
+2004-07-22 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py: Use support.run_tests as the main
+ function when running asa script.
+
+2004-07-22 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mf_export.py: Added "import os"
+ Removed the old "import Thuban.UI.mainwindow" code.
+ (tbextent_to_map): Removed the extra function and at the code direct
+ to "thuban_to_map" function.
+ (write_creatorcomment): Added. Now a short comment is added to the
+ beginning of an generated mapfile.
+ (export_mapfile): Now the Path and filename are saved in to variables,
+ and not together in one variable. This is needed for the new
+ write_creatorcomment function.
+
+ * Extensions/umn_mapserver/mf_import.py (import_mapfile): Added the
+ import module "re". Also added Range and the ClassGroupRange import
+ from Thuban. Both are needed for the new range expression import.
+ (create_rangeexpression): Added. Creates a Range Expression in Thuban
+ style from a given mapfile expression.
+ (added_rasterlayer): Make some small code changes. The shapepath is
+ now stored in an extra variable and the clazz_name is set empty if no
+ class name set in the mapfile.
+ Changed the Error message for Range Expressions, becaus the new
+ function create a error string which will be shown in the dialog.
+
+ * Extensions/umn_mapserver/test/test_mapserver.py: Added a test for the
+ range expression import.
+
+2004-07-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/umn_mapserver/README: Added hint that
+ installation as root can be avoided. Removed all tabs.
+
+2004-07-16 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py
+ (ViewPortTest.test_changing_map_projection): Check that changing
+ the projection of an empty map shown in a viewport doesn't lead to
+ exceptions in the viewport's handler for the
+ MAP_PROJECTION_CHANGED messages
+
+ * Thuban/UI/viewport.py (ViewPort.map_projection_changed): Only
+ try to keep the same region visible when the map actually contains
+ something
+
+2004-07-15 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py: Added a function to get the
+ mappath directly from the mapobj. Is needed because of the changes
+ in mf_import.py.
+ (MF_Layer.add_thubanclass): Added a new comment.
+ (MF_Map.set_extent): Fixed a bug with exporting empty mapobj. If the
+ mapobj is empty there is no extent get from thuban an so no one can
+ set to th mapobj.
+
+ * Extensions/umn_mapserver/mf_import.py (import_mapfile): Updated
+ the discription.
+ Split the funktion in to three smaller ones. The new functions are
+ add_rasterlayer, add_polygonlayer and select_layer2import.
+ Removed the mapfilepath and filepath initialisation, because its know
+ include in the new functions.
+ Now nothing will be imported if cancel is pressed in the
+ layer choice dialog.
+
+2004-07-14 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py: Added ClassGroupDefault to
+ import.
+ (MF_Symbolset): Removed the extra variable for numsymbols.
+ (MF_Class.__init__): Added a comment to the exception clause.
+ Removed the extent init, because it was not needed anymore.
+ (MF_Layer.add_thubanclass): Added the code to set the class name to
+ the expression value from thuban if no label is defined.
+ Added the code to export Range expressions from thuban to the mapfile.
+ (MF_Map.set_extent): Removed the exception and replace it by some if
+ code. If the size of a map is not defined the size will be set to 1,1.
+ This is necessary because if the extent is set, mapscript checks if
+ the size is greater than zero.
+ (MF_Web): Added the get and set function for the template.
+
+ * Extensions/umn_mapserver/mf_export.py: Added the function to check
+ if a mapobject exists and used it to set the status of the menu items.
+ If no mapfile exists the settings could not be edditied.
+ Define after which menuitem the exportitem will include.
+
+ * Extensions/umn_mapserver/mf_handle.py: Removed the import
+ Thuban.UI.mainwindow clause, because it is not needed.
+ Added the command Refresh() to all "OnChangeColor()" functions,
+ because the color preview window was not updated on a color change.
+ Added the function to check if a mapobject exists and used it to set the
+ status of the menu items. If no mapobject exists the settings could not
+ be edditied.
+ (Map_Dialog): Moved the imagetype selector from the
+ Outputformat_Dialog to Map_Dialog and removed Outputformat_Dialog.
+ (Web_Dialog): Removed the name label and added the template textbox.
+
+ * Extensions/umn_mapserver/mf_import.py (import_mapfile): Replace
+ the exception handling on loading the layers by an if statement. It
+ is not necessary to us the exception there.
+ The Filepath creation now use os.path.join to build the path.
+
+ * Extensions/umn_mapserver/test/test_mapserver.py: Moved the testMap
+ definition from global to the setUp function. Now the testMap will
+ initialize new on each test.
+
+ * Extensions/umn_mapserver/sample/iceland.map: Include three new
+ classes in the Line Layer, to test logical Expressions.
+ Set the status of the class "Point9" in the Point Layer to off
+
+2004-07-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/baserenderer.py
+ (BaseRenderer.render_map_incrementally): Fix a logic bug in the
+ optimization that tries not to draw layers under a raster layer.
+ The bug was harmless. All it effectively did was to produce The a
+ strange messages about not being able to draw Layer instances for
+ all vector layers below a raster layer which would be invisible
+ anyway because the raster layer currently always covers the entire
+ window
+
+2004-07-08 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py: Added code to generade and get
+ a list of supported outputformats. This formats are not alle supported
+ because there is no possibility to get the outputformat without the
+ name known. Make some formal changes to the code.
+ (MF_Map.set_name()): Fixed a bug if the name is None.
+
+ * Extensions/umn_mapserver/mf_handle.py: Removed the image_type import
+ statement, because its not needed anymore. The Outputformat is now
+ given as string from the object. Make some formal changes to the code.
+
+ * Extensions/umn_mapserver/test/test_mapserver.py: Added new test for
+ most of the new setting which were added during the last changes.
+ Removed the MF_Size Test.
+
+ * Extensions/umn_mapserver/test/test.map: Added a new class to the
+ cultural Layer to test expressions and the the status of that layer
+ from on to default.
+ Changed the data path the the correct Thuban Data
+ Added the Outputformat Object and Symbol Object
+
+2004-07-07 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py: Added some new
+ settings to edit (outputformat, label, imagetype)
+
+ * Extensions/umn_mapserver/mf_handle.py: Added some setting to
+ the Label Dialog and add the OutputDialog.
+ Make some changes to the code order.
+
+2004-07-06 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/mapfile.py: Added the symbolObj, pointObj
+ and line Obj and add the scalebar_status_type, scalebar_style_type and
+ scalebar_position_type.
+ Added the symbol- and symbolsetObject (MF_Symbol,MF_Symbolset). The
+ are only used to create a Symbol like the circle in Thuban.
+ Added the scalebarObject (MF_Scalebar)
+ (MF_Class): Added set_status and get_status.
+ (MF_Layer.add_thubanclass): Added code to set the class status
+ (MF_Map): Added code to handle the symbols and scalebar
+ (MF_Label): Added the set_partials and get_partials functions
+
+ * Extensions/umn_mapserver/mf_export.py: Added MF_Symbol to import
+ from mapfile. Added a function to create a circle object like the one
+ from thuban if no one exists.
+
+ * Extensions/umn_mapserver/mf_handle.py: All colors are now set when
+ press ok in the assosiated dialog and not at the end of the
+ colordialog.
+ Added the Dialog for the Scalebar.
+ (Label_Dialog): Added the offset option
+
+ * Extensions/umn_mapserver/mf_import.py: Added code to import the
+ status of the Classes.
+ Fixed a bug with the projection. Now the to_meter parameter will be
+ added to the Projection only if it doesn't exists.
+
+2004-07-01 Jan Schüngel <jschuengel at intevation.de>
+
+ Added the functionality to handle the content thuban is not
+ able to handle directly.
+
+ * Extensions/umn_mapserver/mf_handle.py: New. This module extents
+ Thuban with the possibility to edit the mapfile content.
+
+ * Extensions/umn_mapserver/mf_import.py: Added the possibility
+ to import mapfiles without any layer selected. So it is possible
+ to edit the other settings in a mapfile.
+ (import_mapfile): Added code to use the editing functions.
+ Added the possibility to import the projection to a layer if one
+ is defined.
+ Status settings (On,Off) will now set in thuban (visible, invisible).
+ fixed a bug with with classnames. If no classname is set in mapfile
+ the value in Thuban will set to the expression.
+
+ * Extensions/umn_mapserver/mf_export.py(export_mapfile): Added the
+ possibility to save a new mapfile or use the old one which is
+ imported or new created.
+ Added code to use the editing functions.
+ Remove some not needed import statements
+
+ * Extensions/umn_mapserver/mapfile.py: Added new types which are
+ need for the editing functions.
+ Added needed set-functions for the editing functions.
+ Added the possibility to export rasterimages.
+ Added new classes (MF_Web, MF_Label, MF_Legend, MF_Symbol,
+ MF_SymbolSet). MF_Symbol and MF_SymbolSet are not needed at the
+ moment.
+ (MF_Class.set_thubanstyle): Now point layers will set to a default
+ symbol to show a circle in mapserver and not only a 1px dot.
+ (MF_Style.__init__): Fixed a bug with the color. Color was not set
+ correct before.
+ (MF_Size): Removed, because it is not needed.
+
+ * Extensions/umn_mapserver/README: Added the hints to use the
+ export and editing functions, too.
+
+ * Extensions/umn_mapserver/sample/iceland.map: Added the
+ new parameter "UNITS METERS".
+ Change the political layer to status OFF.
+
+ * Extensions/umn_mapserver/sample/README: Added some
+ more details to setup the sample in the MapServer.
+
+2004-06-26 Bernhard Reiter <bernhard at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py:
+ Removed class VFile and used standard StringIO instead.
+
+2004-06-23 Jan Schüngel <jschuengel at intevation.de>
+
+ Add the export function to the umn_mapserver extension.
+
+ * Extension/umn_mapserver/mf_export.py: New. This module extents
+ Thuban with the possibility to export the Thuban content.
+
+ * Extensions/umn_mapserver/mapfile.py: Expand the classes to use
+ with the export module. Especially added the possibility to
+ add thuban objects directly to the map objects.
+
+ * Extensions/umn_mapserver/mf_import.py: Removed the wxCHANGE_DIR,
+ because of the hint from Bernhard Herzog.
+ Corrected the handling of absolute pathnames.
+ Changed the Text of the Menu-Item, now the beginning is upper case.
+
+ * Extensions/umn_mapserver/README: Added the --with-tiff statement.
+
+2004-06-16 Jan Schüngel <jschuengel at intevation.de>
+
+ Add a sample and make some changes.
+
+ * Extension/umn_mapserver/mf_import.py: Changed the wxPython.wx
+ import from * to explicit used statements. Changed the
+ Thuban.UI.mainwindow import phrase, too.
+ (import_mapfile):Corrected a clerical mistake.
+ Added wxCHANGE_DIR in OpenFile Dialog.
+ Added a MultipleChoiceDialog, to select the layers to load from
+ mapfile into thuban. Thereby the projection is only set if one layer
+ is selected.
+ Added the possibility to handle relative pathnames which uses
+ up-level references.
+ Removed some doubled code.
+ Corrected an error with integer values used as label in thuban
+ ClassGroup.
+
+ * Extensions/umn_mapserver/sample: New.
+
+ * Extensions/umn_mapserver/sample/README: New. Describes the
+ usage of the sample files.
+
+ * Extensions/umn_mapserver/sample/iceland.map: New. This is
+ a suitable .map-file for the iceland data.
+
+ * Extensions/umn_mapserver/sample/index.html: New. The template
+ for the mapfile.
+
+ * Extensions/umn_mapserver/sample/iceland.html: New. Initialisation
+ file for the Iceland Application on web.
+
+ * Extensions/umn_mapserver/README: Corrected a inaccuracy and added
+ some details.
+
+ * Extensions/umn_mapserver/test/test_mapserver
+ (mapserver_import_Test_generalClasses.test_MF_Color):
+ Corrected the thubancolor test.
+
+2004-06-15 Jan Schüngel <jschuengel at intevation.de>
+
+ * Extensions/umn_mapserver/README: New. Install instruction.
+
+2004-06-14 Bernhard Reiter <bernhard at intevation.de>
+
+ * libraries/thuban/cpl_mfile.h: Added copyright header.
+
+ * libraries/thuban/ cpl_mfile.cpp, cpl_mfile.h: Added non-protecting
+ Free Software License so that it is most useful with gdalwarp
+ and bmpdataset.
+
+2004-06-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/multiplechoicedialog.py (__version__): Add missing
+ import of wxPython.wx itself (as opposed to the contents of
+ wxPython.wx). For some reason wxPython.wx is available as
+ wxPython.wx.wx in at least some 2.4 releases. Fixes RT#2482
+ wrt. wxPython 2.4.
+
+2004-06-10 Jan Schüngel <jschuengel at intevation.de>
+
+ Initial version of new extension "umn_mapserver". This extension aims
+ to manage configuration for the UMN MapServer application. This
+ inital version just imports the .map-files and displays all, Thuban is
+ capable of.
+
+ * Extensions/umn_mapserver, Extensions/umn_mapserver/test: New.
+
+ * Extensions/umn_mapserver/test/README: New. Describes how to run the
+ tests.
+
+ * Extensions/umn_mapserver/test/test.map: New. This is a test
+ .map-file for automated tests of the umn_mapserver extension of
+ Thuban.
+
+ * Extensions/umn_mapserver/test/test_mapserver.py: New. Tests for
+ UMN Mapserver classes.
+
+ * Extensions/umn_mapserver/__init__.py: New. Init to make this
+ directory a package.
+
+ * Extensions/umn_mapserver/mapfile.py: New. Classes to represent
+ '.map'-file objects.
+
+ * Extensions/umn_mapserver/mf_import.py: New. This module extends
+ Thuban with the possibility to handle UMN MapServer mapfiles.
+
+2004-06-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.TreeInfo): Convert the bounding box
+ to a tuple before using it as arguments to the % operator. This
+ fixes the formatting issue filed in RT#2239 on 2004-01-13 and
+ reported today on thuban-list by Jan Schüngel
+
+ * test/test_layer.py (TestLayerModification.setUp): Save the
+ filename as an instance variable so we can refer to it in tests
+ (TestLayerModification.test_tree_info): Uncomment this method
+ again and make it work. This tests for the formatting issue
+ filed in RT#2239 on 2004-01-13
+
+2004-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/baserenderer.py: Fix some typos.
+
+2004-05-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/gns2shp/gns2shp.py (gns2shp): Fixed a bug
+ by increasing a field size.
+
+2004-05-17 Bernhard Herzog <bh at intevation.de>
+
+ Update to newest shapelib and get rid of Thuban specific
+ extensions, i.e. use the new DBFUpdateHeader instead of our
+ DBFCommit kludge
+
+ * libraries/shapelib/shpopen.c: Update to version from current
+ shapelib CVS.
+
+ * libraries/shapelib/shapefil.h: Update to version from current
+ shapelib CVS.
+
+ * libraries/shapelib/dbfopen.c: Update to version from current
+ shapelib CVS.
+ (DBFCommit): Effectively removed since shapelib itself has
+ DBFUpdateHeader now which is better for what DBFCommit wanted to
+ achieve.
+ We're now using an unmodified version of dbfopen.
+
+ * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
+ value '1' to the Lib.dbflibc extension. This simply reflects the
+ shapelib and pyshapelib updates
+
+2004-05-16 Jan-Oliver Wagner <jan at intevation.de>
+
+ Finished introduction of Menu.FindOrInsertMenu.
+
+ * Extensions/drawshape/drawshape.py: Add the command
+ to the experimental menu additionally to the toolbar.
+
+ * Extensions/svgexport/svgsaver.py: Use FindOrInsertMenu() instead of
+ finding menu on its own.
+
+ * Doc/manual/thuban-manual.xml: updated sample file
+ to use FindOrInsertMenu().
+
+ * Examples/simple_extensions/hello_world.py: Use FindOrInsertMenu()
+ instead of finding menu on its own.
+
+2004-05-11 Jan-Oliver Wagner <jan at intevation.de>
+
+ * test/test_menu.py (MenuTest.test): Added testing
+ of method Menu.FindOrInsertMenu.
+
+2004-05-10 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introduce and use Menu.FindOrInsertMenu.
+
+ * Thuban/UI/menu.py (Menu.FindOrInsertMenu): New. Find a
+ given menu or, if not found, insert it.
+
+ * Extensions/bboxdump/bboxdump.py, /Extensions/gns2shp/gns2shp.py,
+ /Extensions/importAPR/importAPR.py, Extensions/profiling/profiling.py,
+ /Extensions/wms/wms.py: Use FindOrInsertMenu() instead of finding
+ menu on its own.
+
+2004-05-06 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introduce a abstract ColorDialog class and remove
+ and outdated file.
+
+ * Thuban/UI/proj4dialog.py: Removed. It is has been
+ replaced by projdialog for quite a while and is not used
+ anymore.
+
+ * Thuban/UI/colordialog.py: New. Abstraction for color selection
+ dialog(s).
+
+ * Thuban/UI/classifier.py (SelectPropertiesDialog.__GetColor):
+ Now calls the abstract ColorDialog instead of wxColourDialog.
+ This also removed the dependency to Color class conversion
+ from this function.
+
+2004-05-04 Frank Koormann <frank at intevation.de>
+
+ * Extensions/bboxdump/__init__.py: Fixed string left over from
+ copying.
+
+ * Extensions/bboxdump/bboxdump.py (bboxdump):
+ Use layer.ShapeStore().AllShapes() to loop over shapes instead of
+ xrange(layer.NumShapes()). Compile the bboxmessage from a list
+ of formatted outputs (string.join) instead of appending to the
+ message. Two progress bar dialogs to report progress on the sometimes
+ lenghty processing.
+
+2004-04-22 Frank Koormann <frank at intevation.de>
+
+ New Extension to dump bounding boxes of all shapes of the selected
+ layer. An optional column can be specified to group the objects,
+ in this case the bounding box is a union of the separate boxes.
+ Dump can be displayed in a ScrolledMessageDialog or written to file.
+ The Extension is simply a combination of available and well tested
+ Thuban functionality.
+
+ * Extensions/bboxdump/__init__.py: New: Init to make this
+ directory a package.
+
+ * Extensions/bboxdump/bboxdump.py: New: Dump bounding boxes of
+ all shapes of the selected layer.
+
+2004-04-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/classgen.py (GenUniquePanel.__init__): Fixed two
+ strings to be i18n now.
+
+2004-04-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ Changing popup menu of legend from direct building
+ to using the Menu construction as used for the mainwindow.
+
+ * Thuban/UI/mainwindow.py: New method commands: layer_to_top,
+ layer_to_bottom, layer_visibility
+ (MainWindow.LayerToTop): New. Put current layer to the top.
+ (MainWindow.LayerToBottom): New. Put current layer to bottom.
+ (MainWindow.HideLayer, MainWindow.ShowLayer, _has_visible_map):
+ Replace 1,0 by True, False.
+ (MainWindow.ToggleLayerVisibility): New. Toggle visibility of
+ current layer.
+ (MainWindow.LayerShowTable): Removed raising of dialog.
+ (_has_selected_layer_visible): New. Support function.
+
+ * Thuban/UI/legend.py: ID_POP_xxx: removed.
+ (LegendPanel.__init__): Removed EVT_MENU bindings.
+ (LegendTree._OnRightClick): Replace direct creation of
+ menu via wx Classes by applying the menu definition
+ as of Menu class of menu.py.
+
+2004-04-16 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/exceptiondialog.py (ExceptionDialog.dialog_layout): Improved
+ button string to stronger clearify that Thuban will be closed when hitting
+ the button.
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Added docstring.
+ Now for layers without a ShapeStore a corresponding message is given
+ to the user, that this layer has no table to show.
+
+2004-04-15 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/layer.py (WMSLayer.setWMSFormat): Need to
+ recalculate the format for the internal render engine as well.
+
+ * Extensions/wms/properties.py (wmsProperties): First start for a
+ properties dialog. It's functional for a first selection of
+ layers, but still has some weired wxWidgets/GTK problems but
+ beautification can be done later.
+
+ * Extensions/wms/layer.py: Added more documentation
+ (WMSLayer.getFormats): New: Return list of supported image formats
+ by the WMS server
+ (WMSLayer.getLayers): New: Return the list of layer names
+ supported by the WMS server
+ (WMSLayer.getLayerTitle): New: Return the title of the named layer
+ (WMSLayer.getWMSFormat): New: Return the image format that is used
+ for WMS GetMap requests
+ (WMSLayer.setWMSFormat): New: Set the image format that is used
+ for WMS GetMap requests
+ (WMSLayer.__init__): Move away from using only one layer to using
+ a list of layers (unsorted at the moment, though).
+ (WMSLayer.getVisibleLayers): New: Return the list of names for all
+ visible layers
+ (WMSLayer.setVisibleLayers): New: Set the list of names for all
+ visible layers
+
+ * Extensions/wms/wms.py: Moved the WMS layer into layer.py in
+ order to establish a clean structure.
+
+ * Extensions/wms/layer.py: Moved the WMS layer into a file on its
+ own in order to establish a clean structure.
+
+2004-04-13 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.grok): Added
+ support for oldstyle (WMS 1.0 apparently) image format
+ specification.
+
+ * Extensions/wms/wms.py (WMSLayer.calcFormat): Reduce the list of
+ supported graphic formats back to JPEG and BMP, PNG and others are
+ too *cough* experimental... Sorry, I meant to filter this out
+ before I committed this part. This should make the WMS extension
+ run from CVS again.
+ (wms_dialog): Reset an empty URL to None so that the subsequent
+ program can depend on this, since the dialog will indeed return an
+ empty URL, causing another declaration of love by Python.
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.getLayerBBox):
+ Whenever a native BoundingBox request cannot be fulfilled, check
+ whether the requested SRS is EPSG:3426, in which case return the
+ LatLonBoundingBox values.
+
+ * Extensions/wms/test/test_parser.py
+ (TestWMSCapabilitiesParser.test_LayerSRS): Added a test for
+ ignoring AUTO:* SRS.
+ (TestWMSCapabilitiesParser.test_LatLonBoundingBoxes_as_bboxes):
+ Added another test method to test whether the LatLonBoundingBox
+ values will be returned if BoundingBox values are requested with
+ SRS set to EPSG:3426.
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.peekLayers):
+ Added rudimentary support for non-EPSG SRS, i.e. ignore them for
+ the moment by placing them into a variable which is currently
+ unused. Also test whether the EPSG SRS is numerical as it should
+ be and add an error message if it is not.
+
+ * Extensions/wms/test/sample.xml: Added AUTO:* SRS since they
+ appear in the real world as well. Since we cannot handle them yet
+ (OGCLib can't either), we will ignore them for the moment.
+
+ * Extensions/wms/parser.py: Use a variable for denoting the sample
+ filename
+ (WMSCapabilitiesParser.peekLayers): Added support for error
+ messages during grok(). They will be aggregated in an array and
+ may be displayed later. We may have to add a classification
+ "Warning" and "Error" to this. That requires more experience,
+ though, since not every error may be lethal.
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Raise the
+ ShowTable() dialog/frame when the user attempts to display it
+ while it has been opened before already and not closed again.
+
+2004-04-11 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/infodialog.py: Adjusted the class documentation
+
+ * Extensions/wms/wms.py (WMSLayer.__init__, WMSLayer.GetMapImg):
+ Switch to using Thuban{Begin,End}BusyCursor instead of the pure
+ wxWidgets variants.
+ (WMSLayer.__init__): The epsg_id variable is named top_srs now.
+
+ * Extensions/wms/infodialog.py: Added an information dialog that
+ will display various information about the WMS current resource,
+ so that additional information such as the title, the abstract,
+ fees and access constraints can be displayed for the user if they
+ are documented in the WMS XML.
+
+2004-04-10 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.grok): Adjusted
+ string handling. It's "foo".lower() and not lower(foo) without
+ lower imported from strings or something.
+
+ * Extensions/wms/wms.py (WMSLayer): Incorporated WMSCapabilities
+ from capabilities.py and parser.py. Implement priority list for
+ supported graphics formats, take care of wbmp != bmp. PNG, TIFF
+ and GIF are supported here, but not yet by main Thuban. Hence,
+ support for them may be removed later. Special contribution to
+ usability: get wxWidgets to change the cursor when we're waiting
+ for data from the network so the user won't start to worry. This
+ causes a redrawing error/warning, though.
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.grok): Unlink
+ the DOM object.
+
+2004-04-01 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/capabilities.py: Adjusted documentation
+ (WMSCapabilities.__init__): Improved documentation, fixed syntax
+ (WMSCapabilities.saveCapabilities): Only catch IOError when
+ handling files
+ (WMSCapabilities.loadCapabilities): Only catch IOError when
+ handling files
+ __main__: corrected variable naming
+ (WMSCapabilities.fetchCapabilities,loadCapabilities): Make this
+ class a specialisation of WMSCapabilitiesParser as well. Also
+ execute grok() after loading or fetching capabilities, if that
+ went well, so that subsequent calls can already access the data.
+ (WMSCapabilities.getVersion): Export the used version of the
+ GetCapabilities request, so we can use it for subsequent calls,
+ i.e. for GetMap requests.
+ (WMSCapabilities.fetchCapabilities): Added proper error handling
+ when the GetCapabilities request failed, so that the surrounding
+ program can act accordingly.
+
+2004-03-30 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/parser.py (WMSCapabilitiesParser.getLayerSRS):
+ Adjusted the getLayerSRS method to return the list of SRSes
+ extracted from <SRS> elements instead of <BoundingBox> elements.
+ Added a bit of documentation as well.
+ (WMSCapabilitiesParser.checkLayerSRS): Removed integrity test
+ since it was only implemented due to a misunderstanding.
+
+ * Extensions/wms/test/test_parser.py
+ (TestWMSCapabilitiesParser.test_LayerSRS): Adjust the tests to
+ reflect the corrected interpretation of the standard: i.e. a layer
+ does not have to define a BoundingBox for all SRSes it supports.
+ Hence the <SRS></SRS> specification is authoritative, not the list
+ of BoundingBoxes.
+ (TestWMSCapabilitiesParser.test_BoundingBoxes): Added a new test
+ to ensure None is returned for a non-existing SRS.
+ (TestWMSCapabilitiesParser.test_grok): Removed test_grok method
+ since it is not applicable anymore. Listing more SRSes in <SRS>
+ elements is valid according to the specs.
+
+2004-03-26 Bernhard Reiter <bernhard at intevation.de>
+
+ * README: Nicer formatting of text. Improved descriptions.
+ Reflected wxWidgets name change.
+
+ * Thuban/UI/about.py: Extended copyright to 2004 and added
+ information about the thuban-devel mailinglist.
+
+2004-03-24 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/capabilities.py: Renamed the class to contain
+ 'WMS', also added a linebreak where required
+
+ * Extensions/wms/parser.py: Finally added the XML parser for the
+ GetCapabilities response.
+
+ * Extensions/wms/test/sample.xml: Adjusted the sample file so that
+ <SRS> elements match the <BoundingBox> elements, except for the
+ layer 'beschriftung'.
+
+ * Extensions/wms/test/test_parser.py: Encode non-ascii strings
+ since Python uses unicode strings internally, otherwise
+ comparisons will fail. Removed tests for getLayerBBoxSRS() since
+ the SRS will be calculated anyway and this method is obsoleted by
+ getLayerSRS(). Denote SRS as strings and not as cardinal numbers.
+ Move loading the sample file into the setUp method. Added a test
+ for finding the integrity problem in the sample response.
+ Improved formatting.
+
+ * Extensions/wms/domutils.py: Added convenience routines for
+ handling of Document Object Model (DOM) nodes.
+
+ * Extensions/wms/test/test_domutils.py: Added a test for the
+ domutils module
+
+2004-03-19 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_parser.py (TestWMSCapabilitiesParser):
+ Moved path detection and adding into a module of its own,
+ adjustpath, which exports thubandir as main Thuban directory.
+
+ * Extensions/wms/test/test_ogclib.py (TestWMSLib): Moved path
+ detection and adding into a module of its own, adjustpath, which
+ exports thubandir as main Thuban directory. Reorganised the
+ module in order to support the SkipTest feature for Thuban test
+ cases.
+
+ * Extensions/wms/test/adjustpath.py: Moved path detection and
+ adding into a module of its own.
+
+2004-03-18 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_parser.py: Added another test for
+ checking whether the WMS XML parser (to be implemented) returns
+ the information we expect. This requires a sample WMS WML file
+ (sample.xml) which has been extracted from the frida server and
+ "improved" manually.
+
+ * Extensions/wms/test/test_ogclib.py: Added legacy code to add the
+ main Thuban directory to the path in order to be able to import
+ random modules. Adjusted the PyOGCLib detection to reuse the
+ information gathered. Also added a note about the PYTHONPATH
+ environment variable.
+
+ * Extensions/wms/test/test_ogclib.py: The format specification is
+ a mime-type, not a graphic format, hence image/jpeg wou ld be the
+ proper format and not JPEG. We'll also have to take care of the
+ encoding of / as %2F.
+
+2004-03-16 Martin Schulze <joey at infodrom.org>
+
+ * Extensions/wms/test/test_ogclib.py: Added a (hopefully)
+ comprehensive test for the getMapURL method, built compare URLs
+ according to the documentation in OGC 01-068r3
+
+ * Extensions/wms/capabilities.py (WMSCapabilities): Added the
+ class WMSCapabilities to manage capabilites, will incorporate
+ parsing the capabilities response and provide details for other
+ classes.
+
+2004-03-12 Bernhard Herzog <bh at intevation.de>
+
+ Support views in addition to normal tables in the postgis
+ shapestore
+
+ * Thuban/Model/postgisdb.py
+ (PostGISShapeStore._fetch_table_information): Add a fallback for
+ the case where the table name is not in the geometry_columns
+ table. This is usually the case for views. Also, set
+ self.shapestore here.
+ (PostGISShapeStore.ShapeType): No need to query the database all
+ the time. The shape type is now determined in
+ _fetch_table_information
+
+ * test/postgissupport.py (PostgreSQLServer.new_postgis_db)
+ (PostgreSQLServer.get_static_data_db, PostGISDatabase.__init__):
+ New parameter to specify views.
+ (PostGISDatabase.has_data): Also compare the views. New views
+ parameter
+ (PostGISDatabase.initdb): Create the views.
+ (PostgreSQLServer.get_default_static_data_db): Add the v_landmarks
+ view
+
+ * test/test_postgis_db.py
+ (TestPostGISShapestorePointFromViews): New. Test a
+ PostGISShapeStore with a view
+ (TestPostGISShapestorePointOIDAsGIDColumn.setUp): Pass the name of
+ the geometry_column explicitly to test whether that works
+
+2004-03-12 Bernhard Herzog <bh at intevation.de>
+
+ Final step for explicit id/geometry columns: Loading and saving
+
+ * Resources/XML/thuban-1.1.dtd: New. Derived from thuban-1.0.dtd
+ with the following changes:
+ (dbshapesource): Two new attributes id_column and geometry_column
+
+ * Thuban/Model/save.py (SessionSaver.write): Use the new dtd
+ (SessionSaver.write_session): Use the new namespace
+ (SessionSaver.write_data_containers): Write the new dbshapesource
+ parameters
+
+ * Thuban/Model/load.py (SessionLoader.__init__): New namespace for
+ the new file format version
+ (SessionLoader.start_dbshapesource): Handle the new db parameters
+
+ * test/test_save.py: Update to the new dtd and namespace
+ (SaveSessionTest.test_save_postgis): Update the NonConnectionStore
+ mock object to provide a working IDColumn method.
+
+ * test/test_load_1_0.py: New. Copy of the test_load.py before
+ today's changes but with the round-trip tests removed.
+
+ * test/test_load_0_9.py: Update doc-string.
+
+ * test/test_load.py: Update all .thuban files to the new dtd and
+ namespace.
+ (TestPostGISLayer.file_contents): Add the new dbshapesource
+ paramters
+
+2004-03-11 Bernhard Herzog <bh at intevation.de>
+
+ Next step for explicit id/geometry columns: User interaction
+
+ * Thuban/UI/dbdialog.py (ChooseDBTableDialog.__init__): Rework how
+ the dialog is constructed. Add combo boxes to select id and
+ geometry column. Rename some instance variables.
+ (ChooseDBTableDialog.GetTable): Return id and geometry column
+ names
+ (ChooseDBTableDialog.OnTableSelect): New. Event handler for
+ selections in the table list
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddDBLayer): Use id_column
+ and geometry_column
+
+ * Thuban/Model/session.py (Session.OpenDBShapeStore): Add the new
+ parameters for id_column and geometry column of PostGISShapeStore
+ here as well.
+
+ * Thuban/Model/postgisdb.py (type_map): Add ROWID psycog type.
+ (_raw_type_map): New. Map raw PostgreSQL type ints to thuban types
+ (PostGISConnection.GeometryTables): Use a better query to
+ determine which relations in the database might be usable for
+ shapestores. Now supports views as well but is more PostgreSQL
+ specific
+ (PostGISConnection.table_columns): New. Somewhat experimental
+ method to let the db dialogs provide lists of columns to users so
+ that they can select id and geometry columns.
+ (PostGISTable.__init__): The default value of the id_column
+ parameter is now None it still means "gid" effectively, though.
+ (PostGISTable.IDColumn): New introspection method to return a
+ column object for the id column
+ (PostGISShapeStore.GeometryColumn): New introspection method to
+ return a column object for the geometry column
+
+ * test/test_postgis_db.py
+ (TestPostGISConnection.test_gis_tables_non_empty):
+ Removed. Subsumed by the new:
+ (TestPostGISConnection.test_gis_tables_with_views_and_tables):
+ New. Tes the GeometryTables and table_columns methods with actual
+ tables and views.
+ (PointTests.test_id_column, PointTests.test_geometry_column):
+ New. tests for the new methods.
+ (TestPostGISShapestorePoint.setUp)
+ (TestPostGISShapestorePointSRID.setUp)
+ (TestPostGISShapestorePointExplicitGIDColumn.setUp): Fill the
+ instance variables needed by the new tests
+
+2004-03-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.GetList): The row
+ numbers given to ReadValue are ordinals.
+
+2004-03-11 Bernhard Herzog <bh at intevation.de>
+
+ Elimiate the requirement for PostGIS tables to have a column
+ called "gid".
+
+ * Thuban/Model/postgisdb.py (PostGISTable.__init__): New parameter
+ id_column to specify which column to use to identify rows. Also
+ new instance variables id_column and quoted_id_column
+ (PostGISTable.RowIdToOrdinal, PostGISTable.RowOrdinalToId)
+ (PostGISTable.ReadRowAsDict, PostGISTable.ReadValue)
+ (PostGISTable.SimpleQuery): Use the id column name provided to the
+ constructor instead of "gid"
+ (PostGISShapeStore.__init__): New parameter id_column analogously
+ to PostGISTable.__init__. This parameter is simply passed through
+ to the base class constructor
+ (PostGISShapeStore._create_col_from_description): Fix typo in
+ doc-string
+ (PostGISShapeStore.Shape, PostGISShapeStore.AllShapes)
+ (PostGISShapeStore.ShapesInRegion): Use the id column name
+ provided to the constructor instead of "gid"
+
+ * test/postgissupport.py
+ (PostgreSQLServer.get_default_static_data_db): New static table
+ landmarks_point_id with an id column != "gid. Update the comments
+ a bit.
+ (skip_if_addgeometrycolumn_does_not_use_quote_ident): Fix typo in
+ doc-
+ (upload_shapefile): New parameter gid_column to use a name other
+ than "gid" for the column to store the shape ids
+
+ * test/test_postgis_db.py (TableTests): New. Mixin-class
+ containing all tests previously in TestPostGISTable. The actual
+ tests are the same but the code is a bit more configurable to
+ allow for different id columns etc.
+ (TestPostGISTable): Derive from TableTests now for the actual
+ tests.
+ (TestPostGISTableExplicitGIDColumn): New. Like TestPostGISTable
+ except that it the landmarks_point_id table to test the id_column
+ parameter
+ (PointTests): Extend the doc-string
+ (TestPostGISShapestorePointExplicitGIDColumn)
+ (TestPostGISShapestorePointOIDAsGIDColumn): New classes derived
+ from PointTests to test the explicit id_column parameter. One
+ tests with the name of the column holding the shape ids, the other
+ uses PostgreSQL's OID column. For the latter a number of methods
+ have to be overwritten to make them independent of the actual id
+ values.
+
+2004-03-08 Silke Reimer <silke at intevation.de>
+
+ Update debian directory:
+
+ * debian/changelog: Added new version.
+ * deiban/rules: Updated management of patches (with cbds)
+ * debian/control: Added cbds to dependencies
+ * debian/patches/*: New. Adds better support for patches of thuban in
+ debian
+ * debian/menu: Syntax of menu changed slightly
+ * debian/setup.py.patch: removed because it has been moved to
+ debian/patechs/setup.py.patch
+
+
+2004-02-26 Bernhard Herzog <bh at intevation.de>
+
+ Create the Doc/technotes directory for text files with information
+ for developers
+
+ * Doc/technotes/README: New. README for the technotes
+
+ * Doc/technotes/coding_guidelines.txt: New. Coding guidelines for
+ Thuban
+
+ * Doc/technotes/release_process.txt: New. Used to be
+ HOWTO-Release. Now slightly adapted to technote formatting style.
+
+ * HOWTO-Release: Removed. It's contents are now in
+ Doc/technotes/release_process.txt
+
+2004-02-25 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/thuban/wxproj.cpp (get_wx_version): New. Return the
+ version of wxWindows the module was compiled with so we can check
+ that against the wxPython version.
+
+ * Thuban/version.py (thuban_branch, thuban_release): New variables
+ controlling which and how Thuban versions are shown. See the
+ comments for details.
+ (verify_versions): Also check that the wx version that wxproj is
+ compiled against matches that of the wxPython we use at runtime
+
+2004-02-20 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/wms/wms.py (epsg_code_to_projection): Use
+ get_system_proj_file to read the epsg projections. The old way
+ depended on the current directory being the top Thuban directory.
+
+2004-02-20 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/test/test_svgmapwriter.py
+ (TestVirtualDC.test_clippath): Remove a debug print
+
+2004-02-20 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/__init__.py: New. Turn
+ Extensions/svgexport into a package.
+
+ * Extensions/svgexport/svgmapwriter.py: Reorder the imports and
+ doc-string a bit. The doc-string must come first, otherwise it's
+ not a doc-string. The __future__ import must be the first thing
+ after the doc-string. Use only double quotes in doc-strings.
+ Single quotes trip up emacs syntax highlighting if the text
+ contains apostrophes.
+
+2004-02-20 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/test/__init__.py,
+ Extensions/svgexport/test/test_svgmapwriter.py: New. Initial test
+ suite for svgexport
+
+ * test/runtests.py (find_test_modules): New. Function with the
+ module finding code from main.
+ (main): Use find_test_modules to figure out the default test
+ modules and take modules from Extensions.svgexport.test too.
+
+2004-02-19 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Make sure
+ the mainwindow has a reference to the map of the initial session.
+ This fixes a bug introduced with the fix for RT#2245
+
+2004-02-19 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/svgexport/svgsaver.py,
+ Extensions/svgexport/svgmapwriter.py,
+ Extensions/svgexport/maplegend.py: Added again. This time in the
+ correct place.
+
+2004-02-17 Bernhard Herzog <bh at intevation.de>
+
+ Fix for RT#2245
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Initialize
+ instance variables before trying to create any windows. Creating
+ windows can start an event loop if e.g. message boxes are popped
+ up for some reason, and event handlers, especially EVT_UPDATE_UI
+ may want to access things from the application.
+ (ThubanApplication.maps_changed): The mainwindow may not have been
+ created yet, so check whether it has been created before calling
+ its methods
+
+ * Thuban/UI/view.py (MapCanvas.OnIdle): Only try to redraw if we
+ have a map
+
+2004-02-17 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_svgmapwriter.py, Extensions/svgsaver.py,
+ Extensions/svgmapwriter.py, Extensions/maplegend.py,
+ extensions/svgexport/svgsaver.py,
+ extensions/svgexport/svgmapwriter.py,
+ extensions/svgexport/maplegend.py: Removed. These files were in
+ the wrong places or didn't work at all.
+
+2004-02-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.Export): Remove accidentally added
+ line
+
+2004-02-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.Export): Avoid UnboundLocalError.
+
+2004-02-15 Markus Rechtien <markus at intevation.de>
+
+ * Extensions/svgexport/svgmapwriter.py: New. Adds the capability
+ to write a session to a file in SVG format.
+ * Extensions/svgexport/svgsaver.py: New. Uses svgmapwriter.py
+ to write a SVG map of a session.
+ * Extensions/svgexport/maplegend: New. Writes a basic maplegend
+ in SVG format for the current session.
+
+2004-02-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddDBLayer): When the layer
+ can't be created, return immediately after displaying the error
+ message.
+
+2004-02-11 Bernhard Herzog <bh at intevation.de>
+
+ Handle postgis tables with more than one geometry column.
+
+ * Thuban/Model/postgisdb.py
+ (PostGISTable._fetch_table_information): Delegate the creation of
+ column objects to a different method so that we can extend that in
+ derived classes
+ (PostGISTable._create_col_from_description): New. Column object
+ creation part of _fetch_table_information
+ (PostGISShapeStore._create_col_from_description): New. Extend
+ inherited method to handle geometry columns
+ (PostGISShapeStore.__init__): New parameter geometry_column to
+ specify which geometry column to use. Optional but mandatory for
+ tables with more than one geometry column
+ (PostGISShapeStore._fetch_table_information): Also use the name of
+ the geometry column when looking for the srid
+ (PostGISShapeStore.ShapeType): Also use the name of the geometry
+ column when looking for the shape type
+
+ * test/test_save.py (SaveSessionTest.test_save_postgis): Adapt
+ NonConnectionStore to changes in the PostGISShapeStore
+
+ * test/test_postgis_db.py
+ (TestPostGISSpecialCases.test_shapestore_two_geom_cols): Test
+ PostGISShapeStore with tables having two geometry columns.
+
+2004-02-10 Bernhard Herzog <bh at intevation.de>
+
+ Fix some postgis problems. What remains to be done is real
+ handling of SRIDs as they affect how reprojection is done
+
+ * Thuban/Model/postgisdb.py (quote_identifier): Fix typo in
+ doc-string
+ (PostGISShapeStore._fetch_table_information): New. Extend
+ inherited method to retrieve srid
+ (PostGISShapeStore.BoundingBox): Handle tables without data.
+ extent yields NULL for those
+ (PostGISShapeStore.ShapesInRegion): Use the srid of the table.
+
+ * test/test_postgis_db.py
+ (TestPostGISSpecialCases.test_shapestore_empty_table): New test
+ for the special case of a table without any data
+ (TestPostGISShapestorePointSRID): New class with tests for a table
+ that uses srids
+ (PolygonTests): Fix a doc-string typo
+
+ * test/postgissupport.py (PostGISDatabase.__init__): New parameter
+ reference_systems with a specification of spacial reference
+ systems to create in the new db.
+ (PostgreSQLServer.new_postgis_db)
+ (PostgreSQLServer.get_static_data_db): New parameter
+ reference_systems to be passed through ultimately to
+ PostGISDatabase. In new_postgis_db also check whether an existing
+ db already has the right srids
+ (PostgreSQLServer.get_default_static_data_db): Add srids and a
+ table that uses srids
+ (PostGISDatabase.initdb): Create the entries for the reference
+ systems
+ (PostGISDatabase.has_data): Add reference_systems parameter to
+ check for those too
+ (upload_shapefile): New parameter srid to create tables with a
+ specific srid
+
+2004-02-06 Frank Koormann <frank at intevation.de>
+
+ * po/pt_BR.po: Fixed charset
+
+2004-02-05 Frank Koormann <frank at intevation.de>
+
+ * po/pt_BR.po: Fixed format string for error message, missing %s
+ added (Thuban/UI/application.py:273)
+
+2004-02-03 Frank Koormann <frank at intevation.de>
+
+ First version of Portuguese (Brazilian) translation
+
+ * po/pt_BR.po: New, translation of pot (2004-01-15 16:07+0300) for
+ Brazilian Portuguese by Eduardo Patto Kanegae.
+
+ * Thuban/UI/about.py (About.__init.py__): Added Eduardo to the list of
+ translators.
+
+
+2004-01-22 Frank Koormann <frank at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added section on installation of
+ Thuban under Win32 systems. Fixed image path references in the postgis
+ section. Some minor source formattings.
+
+2004-01-21 Frank Koormann <frank at intevation.de>
+
+ Make Thuban remember path selections (at least for one application run).
+
+ * Thuban/UI/application.py (Application.OnInit): Initialize path as a
+ attribute of application object. Path is a dictionary of
+ strings, currently with the items "data" and "projection".
+ (Application.SetPath): New, stores path for the specified item.
+ (Application.Path): New, return path for the specified item.
+
+ * Thuban/UI/mainwindow.py
+ (MainWindow.OpenSession, MainWindow.SaveSessionAs,
+ MainWindow.AddLayer, MainWindow.AddRasterLayer,
+ MainWindow.TableOpen): Access "data" path information of the
+ application.
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnImport, ProjFrame._OnExport):
+ Access "projection" path information of the application.
+
+2004-01-05 Bernhard Herzog <bh at intevation.de>
+
+ * po/ru.po: Updated translations from Alex Shevlakov
+
+2004-01-05 Bernhard Herzog <bh at intevation.de>
+
+ * po/Makefile, po/README: Move the description of how to generate
+ the translation statistics to the README.
+
+2003-12-23 Bernhard Herzog <bh at intevation.de>
+
+ * NEWS: Update for 1.0.0
+
+ * po/it.po: Another update from Maurizio Napolitano
+
+2003-12-23 Bernhard Herzog <bh at intevation.de>
+
+ * po/it.po: Updated translation from Maurizio Napolitano
+
+2003-12-23 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.__init__): Mark one more string
+ for translation
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableRename)
+ (MainWindow.RenameMap, MainWindow.RenameLayer): Mark some more
+ strings for translation
+
+ * po/de.po: Update with the newly marked strings.
+
+2003-12-22 Bernhard Herzog <bh at intevation.de>
+
+ * HOWTO-Release: Fix the places where version numbers have to be
+ updated
+
+2003-12-22 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (setup call): 1.0.0, yeah!
+
+ * Thuban/version.py (longversion): 1.0.0, yeah!
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Accept the
+ 1.0.0 namespace too
+
+ * Thuban/Model/save.py (SessionSaver.write_session): Save with
+ 1.0.0 namespace
+
+ * test/test_load.py (LoadSessionTest.dtd)
+ (TestSingleLayer.file_contents)
+ (TestNonAsciiColumnName.file_contents)
+ (TestLayerVisibility.file_contents)
+ (TestClassification.file_contents, TestLabels.file_contents)
+ (TestLayerProjection.file_contents)
+ (TestRasterLayer.file_contents, TestJoinedTable.file_contents)
+ (TestLabelLayer.file_contents, TestPostGISLayer.file_contents)
+ (TestPostGISLayerPassword.file_contents)
+ (TestLoadError.file_contents, TestLoadError.test): Update for
+ 1.0.0 namespace
+
+ * test/test_save.py (SaveSessionTest.dtd)
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table)
+ (SaveSessionTest.test_save_postgis): Update for 1.0.0 namespace
+
+2003-12-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.start_label): Make sure the
+ alignment flags are byte strings not unicode and that they have
+ valid values
+
+ * test/test_load.py (TestLabelLayer): New. Test loading (and
+ indirectly saving) of maps with labels.
+
+2003-12-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tableview.py (TableGrid.OnDestroy)
+ (TableGrid.__init__): Handle EVT_WINDOW_DESTROY in the grid to
+ unsubscribe all subscribers.
+ (LayerTableFrame.OnDestroy): Do not unsubscribe any messages from
+ self.grid since it may already have been destroyed.
+ Fixes RT #2256
+
+2003-12-19 Bernhard Herzog <bh at intevation.de>
+
+ * po/fr.po, po/es.po: Updated translations from Daniel Calvelo
+
+2003-12-16 Bernhard Herzog <bh at intevation.de>
+
+ * debian/bitmappath.patch, debian/setup.py.patch:
+ added to ensure compliance with FHS for debian
+ * debian/rules, debian/changelog:
+ added patches in rules to ensure compliance with FHS for debian
+
+2003-12-16 Bernhard Herzog <bh at intevation.de>
+
+ * po/Makefile (mo): Make the output a bit nicer so that it prints
+ statistics about the translations. Add a comment how produce even
+ nicer statistics with sed.
+
+2003-12-09 Frank Koormann <frank at intevation.de>
+
+ * Resources/Projections/defaults.proj:
+ French projection sample with correct accents (UNICODE).
+
+2003-12-05 Bernhard Herzog <bh at intevation.de>
+
+ * MANIFEST.in: Add the devtools directory
+
+ * setup.py (setup call): Use license instead of licence. This
+ silences a deprecation warning on Python 2.3
+
+2003-12-05 Frank Koormann <frank at intevation.de>
+
+ Documentation synced with 1.0rc1
+
+ * Doc/manual/thuban-manual.xml:
+ Minor formatting changes and references to database layers .
+ Introduction.Internationalization: New section on i18n.
+ MapManagement.AddingandRemovingLayers: Added item on database layers.
+ MapManagement.TheLegend: Added section and screenshot on popup menu.
+ ProjectionManagement: Updated screenshot and sentence on EPSG.
+ Appendix.SupportedDataSources: Added PostGIS.
+ Appendix.WorkingwithPostGIS: New section.
+
+ * Doc/manual/images/6_projection.png: Updated screenshot including
+ EPSG checkboxes.
+
+ * Doc/manual/images/3_5_popup_menu.png: New, popup menu screenshot.
+
+ * Doc/manual/images/app_postgis_add_layer.png,
+ Doc/manual/images/app_postgis_db_add.png,
+ Doc/manual/images/app_postgis_db_management.png:
+ New screenshots focussing on database layers
+
+2003-12-05 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/projdialog.py (load_user_proj): If user.proj is missing
+ write warning to stderr instead of rising a warning dialog
+
+2003-12-03 Bernhard Herzog <bh at intevation.de>
+
+ Fix for RT #2243
+
+ * Thuban/UI/mainwindow.py (MainWindow.has_selected_shape_layer):
+ New. Like has_selected_layer but for shape layers only
+ (_has_selected_shape_layer): New. Like _has_selected_layer but for
+ shape layers only
+ (layer_show_table command, layer_jointable command): Use these
+ commands should only be available for shape layers
+
+2003-12-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.Unsubscribe): Deal with
+ publishers that are wx objects and may have been destroyed by wx
+ already. Fixes RT #2242.
+
+2003-12-03 Bernhard Herzog <bh at intevation.de>
+
+ * po/ru.po: Updates from Alex Shevlakov
+
+2003-12-03 Silke Reimer <silkeintevation.de>
+
+ * debian/control, debian/changelog: Added gdal-support to
+ debian package, updated to new thuban version
+
+
+2003-12-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Lib/version.py: New. Module for version number
+ manipulations. The version of make_tuple here also deals better
+ with more unusual version number strings, such as e.g.
+ "1.2+cvs20031111"
+
+ * Thuban/version.py (make_tuple): Removed. It's now in
+ Thuban.Lib.version. Use that implementation instead.
+
+ * test/test_lib_version.py: New. Tests for Thuban/Lib/version.py
+
+2003-12-02 Bernhard Herzog <bh at intevation.de>
+
+ * MANIFEST.in: Add debian files
+
+ * setup.py (setup call): Add packages for the Extensions so that
+ they're installed too
+ (data_files): Add READMEs and sample data from some Extensions
+
+ * NEWS: Add note about the extensions in binary packages
+
+2003-12-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/save.py (SessionSaver.write_session): Save files
+ with the thuban-1.0rc1
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Recognize the
+ thuban-1.0rc1 namespace too
+
+ * test/test_save.py (SaveSessionTest.dtd)
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table)
+ (SaveSessionTest.test_save_postgis): Update to thuban-1.0rc1
+ namespace
+
+ * test/test_load.py (LoadSessionTest.dtd): Update to thuban-1.0rc1
+ namespace
+ (TestSingleLayer.file_contents)
+ (TestNonAsciiColumnName.file_contents)
+ (TestLayerVisibility.file_contents)
+ (TestClassification.file_contents, TestLabels.file_contents)
+ (TestLayerProjection.file_contents)
+ (TestRasterLayer.file_contents, TestJoinedTable.file_contents)
+ (TestPostGISLayer.file_contents)
+ (TestPostGISLayerPassword.file_contents)
+ (TestLoadError.file_contents, TestLoadError.test): Update to
+ thuban-1.0rc1 namespace
+
+2003-12-01 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (proj4_prefix, wx_prefix, gdal_prefix): Fix these for
+ nt to better match Intevation's current w32 setup
+
+ * HOWTO-Release: Add note about updating MANIFEST.in
+
+ * MANIFEST.in: Add the Extensions
+
+ * NEWS: Update for 1.0rc1
+
+2003-12-01 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddLayer): Change the wild
+ cards for the dialog so that shapefiles ending in all uppercase
+ SHP are listed too
+
+2003-11-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/version.py (longversion): Update to 1.0rc1
+
+ * setup.py (setup call): Update version to 1.0rc1. Use the
+ thuban at intevation.de email address as author email instead of my
+ personal one.
+
+2003-11-28 Bernhard Herzog <bh at intevation.de>
+
+ * po/de.po: Update german translation.
+
+2003-11-28 Bernhard Herzog <bh at intevation.de>
+
+ Unify the filenames stored in .thuban files so that the .thuban
+ files are more platform independend
+
+ * Thuban/Model/save.py (unify_filename): New. Unify filenames so
+ that they can be used on both windows and unix
+ (SessionSaver.prepare_filename): New. Handle all filename
+ transformations for filenames stored in the thuban file
+ (SessionSaver.write_data_containers, SessionSaver.write_layer):
+ Use prepare_filename
+
+ * test/test_save.py (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table): Filenames are always stored
+ with slashes on all currently supported platforms so adapt all
+ tests to this
+
+ * test/test_load.py (LoadSessionTest.filenames): With the new
+ filename scheme the filenames in the tests should be
+ understandable on all currently supported platforms so we turn
+ this into an empty list because we don't have to normalize them
+ anymore
+
+2003-11-28 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_layer.py (TestLayer.test_arc_layer_with_projection):
+ Add the ellipsoid to the projection since some Proj versions
+ complain if it's missing.
+
+2003-11-27 Bernhard Herzog <bh at intevation.de>
+
+ Corect some bounding box projection problems
+
+ * Thuban/Model/proj.py (Projection.InverseBBox): New. Inverse
+ version of ForwardBBox
+ (Projection._transform_bbox): New. common implementation of
+ ForwardBBox and InverseBBox
+ (Projection.ForwardBBox): Use _transform_bbox.
+
+ * test/test_proj.py (TestProjection.test): Add test for
+ InverseBBox
+
+ * Thuban/Model/layer.py (Layer.LatLongBoundingBox)
+ (Layer.ShapesBoundingBox, RasterLayer.LatLongBoundingBox): Use the
+ new InverseBBox method to determine the unprojected bounding box
+ (Layer.ShapesInRegion): Use the ForwardBBox method to project the
+ bbox.
+
+ * test/test_layer.py (TestLayer.test_point_layer_with_projection):
+ Removed.
+ (TestLayer.test_arc_layer_with_projection): New. This test is
+ better able to test whether bounding boxes are projected correctly
+ than test_point_layer_with_projection
+
+ * Thuban/UI/viewport.py (ViewPort.map_projection_changed): Use
+ InverseBBox to unproject bboxes
+
+2003-11-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Make sure we have ASCII
+ source code.
+
+2003-11-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.__getattr__): Removed. It was only
+ there for backwards compatibility and all code relying on that
+ should have been updated by now.
+
+2003-11-25 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_load.py (TestClassification.test): Add the missing
+ round trip test.
+ (TestClassification.file_contents): Update to the newest file
+ format
+
+2003-11-25 Bernhard Herzog <bh at intevation.de>
+
+ Add very experimental (and possibly dangerous) extension to draw
+ polygons:
+
+ * Extensions/drawshape/README: New. Brief installation
+ instructions
+
+ * Extensions/drawshape/drawshape.py: New. Implementation of the
+ drawshape extensions
+
+ * Extensions/drawshape/patch.diff: Patch to apply before the
+ extension can be used.
+
+2003-11-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/data.py (ShapefileStore._open_shapefile)
+ (ShapefileStore.__init__): Factor opening the shapefile into a
+ separate method (the new _open_shapefile). This makes the code a
+ bit more readable but the real reason is that it makes some evil
+ hacks easier. :-)
+
+2003-11-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.check_attrs): If no
+ converter is specified for an attribute assume it's a string
+ containing only Latin1 characters. Update doc-string accordingly.
+ This change should fix many places where unicode objects might
+ accidentally enter Thuban.
+
+ * test/test_load.py (TestNonAsciiColumnName): New test to check
+ what happens with column names in DBF files that contain non-ascii
+ characters
+
+2003-11-21 Bernhard Herzog <bh at intevation.de>
+
+ Enable the experimental attribute editing again and introduce a
+ command line switch to actually activate it
+
+ * Thuban/UI/main.py (options): New. Container for options set on
+ the commmand line
+ (main): Add the --enable-attribute-editing flag.
+
+ * Thuban/UI/identifyview.py (IdentifyView.__init__): If attribute
+ editing is enabled use the grid ctrl which allows editing of the
+ values
+
+ * Thuban/Model/transientdb.py (AutoTransientTable.write_record):
+ New. Just delegate this to the underlying table.
+
+2003-11-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py (ProjFileReadTests.test_read_unreadable_file):
+ Skip this test if run under non-posix systems since it only works
+ there
+
+2003-11-19 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/resource.py: Rework the way gdal support is
+ determined so that we can give a reason in the about why gdal is
+ not supported.
+ (gdal_support_status): New. Variable holding a string with the
+ reason for no gdal support
+
+ * Thuban/UI/about.py (About.__init__): Add the reason why gdal is
+ not supported to the message
+
+2003-11-19 Bernhard Herzog <bh at intevation.de>
+
+ Remove the old table interface and its test cases
+
+ * Thuban/Model/table.py (OldTableInterfaceMixin): Removed.
+ (DBFTable, MemoryTable): Do not derive from OldTableInterfaceMixin
+ anymore
+
+ * Thuban/Model/transientdb.py (TransientTableBase)
+ (AutoTransientTable): Do not derive from OldTableInterfaceMixin
+ anymore
+
+ * test/test_table.py: Removed since the old interface it tests is
+ gone.
+
+ * test/runtests.py (main): The old table interface is gone and
+ with it the deprecation warnings so remove the code that turns
+ these warnings into errors
+
+2003-11-19 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_table.py: Revert to revision 1.5 again. Changing the
+ tests to use the new table interface is completely wrong since the
+ whole purpose of the tests in this module is to test the old
+ interface.
+
+2003-11-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (PostGISConnection.MatchesParameters):
+ New. Test whether the connection matches a set of connection
+ parameters
+
+ * Thuban/UI/dbdialog.py (DBFrame.conns_changed): Fix doc-string
+ (DBFrame.OnAdd): Use the new MatchesParameters method when looking
+ for existing connections with the same parameters and break out of
+ the loop correctly.
+
+ * test/test_postgis_db.py (TestBriefDescription)
+ (TestPostGISSimple.test_brief_description): Rename
+ TestBriefDescription to TestPostGISSimple and the test method to
+ test_brief_description so that we can add more test methods.
+ (TestPostGISSimple.test_matches_parameters): New. Test the new
+ MatchesParameters method
+
+2003-11-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Lib/connector.py (Publisher): Introduce a new flag,
+ _was_destroyed, to indicate whether an publisher instance has
+ already been destroyed.
+ (Publisher.Unsubscribe): Only disconnect if the publisher has not
+ been destroyed yet.
+ (Publisher.Destroy): Set the _was_destroyed flag to true.
+
+ * test/test_connector.py
+ (TestPublisher.test_unsubscribe_after_destroy): New. Test that
+ calling Unsubscribe after Destroy doesn't raise an exception
+
+2003-11-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyView.selected_shape): Fix
+ typo in doc-string
+
+2003-11-13 Bernhard Herzog <bh at intevation.de>
+
+ Quote table and column names properly for postgis.
+
+ * Thuban/Model/postgisdb.py (quote_identifier): New. Function to
+ quote an identifier for use in an sql statement
+ (PostGISColumn.__init__): Add the quoted_name attribute
+ (PostGISTable.__init__): New instance variable quoted_tablename
+ (PostGISTable._fetch_table_information): Use the quoted table
+ name. New isntance variable quoted_geo_col with a quoted version
+ of geometry_column
+ (PostGISTable.NumRows, PostGISTable.RowIdToOrdinal)
+ (PostGISTable.RowOrdinalToId): Use the quoted table name
+ (PostGISTable.ReadValue, PostGISTable.ValueRange)
+ (PostGISTable.UniqueValues, PostGISTable.SimpleQuery)
+ (PostGISShapeStore.BoundingBox, PostGISShapeStore.Shape)
+ (PostGISShapeStore.AllShapes, PostGISShapeStore.ShapesInRegion):
+ Use quoted table and column names
+
+ * test/test_postgis_db.py (TestPostGISSpecialCases)
+ (TestPostGISIgnoredColumns): Rename the class to
+ TestPostGISSpecialCases because that better describes the new
+ cases
+ (TestPostGISSpecialCases.test_unsupported_types)
+ (TestPostGISSpecialCases.test): Rename the method to
+ test_unsupported_types because we need a more descriptive name now
+ that there are more methods
+ (TestPostGISSpecialCases.test_table_name_quoting)
+ (TestPostGISSpecialCases.test_column_name_quoting)
+ (TestPostGISSpecialCases.test_shapestore_name_quoting): New test
+ cases to test quoting of table and column names in PostGISTable
+ and PostGISShapeStore
+
+ * test/postgissupport.py
+ (skip_if_addgeometrycolumn_does_not_use_quote_ident): New. Skip if
+ AddGeometryColumn desn't support table or column names with sapces
+ or double quotes
+
+2003-11-12 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/wms/__init__.py: New: Init to make this
+ directory a package.
+
+ * Extensions/wms/wms.py: New: Provide layers via OGC WMS.
+
+2003-11-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/resource.py (EPSG_DEPRECATED_PROJ_FILE): New.
+ Constant for the file woth deprecated epsg projections
+ (get_system_proj_file): Update doc-string
+
+ * Thuban/UI/projdialog.py (ProjFrame.build_dialog): Add a space
+ above the EPS widgets, introduce a check box for the deprecated
+ eps projections and a label for the epsg widgets
+ (ProjFrame._OnShowEPSG): Handle the deprecated EPSG projections
+ too
+
+2003-11-11 Bernhard Herzog <bh at intevation.de>
+
+ Avoid warnings when run under Python 2.3
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.draw_point_shape)
+ (BaseRenderer.draw_label_layer): Coordinates must be ints.
+
+ * Thuban/UI/renderer.py (MapRenderer.make_point): Turn this into a
+ real method so that we can convert to int.
+ (MapRenderer.label_font): The font size mist be an int.
+
+ * Thuban/UI/common.py (Color2wxColour): The color values must be
+ ints. Also, remove the unnecessary asserts.
+
+ * test/test_load_0_8.py (TestUnicodeStrings.file_contents)
+ (TestUnicodeStrings.test): Python source code should not contain
+ non-ascii characters unless an encoding is specified in the file.
+ Therefore use \x escapes in the string literals for non-ascii
+ characters.
+
+2003-11-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/resource.py (get_system_proj_file): Add a filename
+ parameter so that this function can be used for all proj files in
+ Resource/Projections
+ (DEFAULT_PROJ_FILE, EPSG_PROJ_FILE): New. Predefined filenames for
+ get_system_proj_file
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__): Instead of one
+ ProjFile self.__sysProjFile use a dictionary of system ProjFile
+ objects self._sys_proj_files
+ (ProjFrame.build_dialog): Adapt to the new changes in the
+ ProjectionList constructor. Add a check button to toggle whether
+ EPSG projections are shown
+ (ProjFrame._OnShowEPSG): New. Handler for the epsg check button
+ events.
+ (ProjFrame.load_user_proj, ProjFrame.load_system_proj): Only show
+ the busy cursor if the files have not yet been loaded by the
+ dialog.
+ (ProjFrame.load_system_proj): Add a parameter for the name of the
+ proj file. Maintain the dictionary of system projections
+ self._sys_proj_files
+
+ * Thuban/UI/projlist.py (ProjectionList): Merge the system_projs,
+ user_projs parameters into one parameter proj_files which is a
+ list of proj files.
+ (ProjectionList._subscribe_proj_files)
+ (ProjectionList._unsubscribe_proj_files): New. Move
+ subscription/unsubscription of projfile messages to separate
+ methods
+ (ProjectionList.Destroy): The unsubscribe is now done in
+ _unsubscribe_proj_files
+ (ProjectionList.update_projections): We now have a list of proj
+ file objects
+ (ProjectionList.SetProjFiles): New method to set a new list of
+ proj file objects
+
+ * test/test_proj.py (ProjFileReadTests.test_get_system_proj_file):
+ Specify explicitly which system proj file to load.
+
+2003-11-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.Destroy): New. Clear all
+ instance variables to cut cyclic references. The GC would have
+ collected the loader eventually but it can happen that it doesn't
+ run at all until thuban is closed (2.3 but not 2.2 tries a bit
+ harder and forces a collection when the interpreter terminates)
+ (load_session): Call the handler's Destroy method to make sure
+ that it gets garbage collected early. Otherwise it will be
+ collected very late if at all and it holds some references to e.g.
+ shapestores and the session which can lead to leaks (of e.g. the
+ temporary files)
+
+ * test/test_load.py (TestSingleLayer.test_leak): New. test for the
+ resource leak in load_session
+
+2003-11-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/baserenderer.py: Add a way to specify how layers in
+ extensions are to be rendered.
+ (_renderer_extensions): New. List with renderer for layers in
+ extensions
+ (add_renderer_extension): New. Add a renderer extension
+ (init_renderer_extensions): New. Init the renderer extensions
+ (BaseRenderer.render_map_incrementally): Search
+ _renderer_extensions for how to draw unknown layer types
+ (BaseRenderer.draw_raster_data): Add format parameter so that
+ formats other than BMP can be drawn
+ (BaseRenderer.draw_raster_layer): Pass an explicit format to
+ draw_raster_data
+
+ * Thuban/UI/renderer.py (raster_format_map): New. Mapping form the
+ strings of the format parameter of draw_raster_data method to wx
+ constants
+ (MapRenderer.draw_raster_data): Add the format parameter and use
+ raster_format_map to map it to the right wxwindows constant for
+ wxImageFromStream
+
+ * test/test_baserenderer.py (SimpleRenderer.draw_raster_data): Add
+ the format parameter and record it
+ (TestBaseRenderer.test_raster_no_projection): check the format
+ paramter of the draw_raster_data method
+ (TestBaseRenderer.test_renderer_extension): New. Test the renderer
+ extension facility
+
+2003-11-07 Bernhard Herzog <bh at intevation.de>
+
+ Tweak the usage of the sqlite database to make common use cases
+ more responsive. In most cases copying the data to the sqlite
+ database takes so long that using sqlite doesn't have enough
+ advantages.
+
+ * Thuban/Model/transientdb.py (TransientTableBase.ValueRange): Add
+ comments about performance and query the min and max in separate
+ statements because only that way will indexes be used.
+ (TransientTableBase.UniqueValues): Add some comments about
+ performance.
+ (AutoTransientTable.ValueRange, AutoTransientTable.UniqueValues):
+ Do not copy the data to the transient DB but use the transient
+ copy if it exists. See the new comments for the performance trade
+ offs
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_auto_transient_table): Make sure that the
+ data is copied to the transient database at some point.
+
+2003-11-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/data.py (ShapefileStore.ShapesInRegion): Bind some
+ globals to locals so that it's a bit faster
+
+2003-11-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/baserenderer.py
+ (BaseRenderer.draw_shape_layer_incrementally): Use the ReadValue
+ method. ReadValue is faster than ReadRowAsDict since it only reads
+ one cell especially now that the dbf file objects actually
+ implement it.
+
+ * Thuban/Model/table.py (DBFTable.ReadValue): Use the new
+ read_attribute method of the dbf objects
+
+2003-11-03 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/profiling/profiling.py (popup_dialog_box): New config
+ variable to indicate whether the result should be shown in a
+ dialog box
+ (profile_screen_renderer, time_screen_renderer): Only show a
+ dialog box if popup_dialog_box is true.
+ (profile_screen_renderer): Flush stdout after the printing the
+ first part of the "profiling..." message
+
+ * Thuban/UI/baserenderer.py
+ (BaseRenderer.draw_shape_layer_incrementally): Cache the pens and
+ brushes for the groups so that they're not created over and over
+ again
+
+ * Thuban/Model/classification.py (Classification.__getattr__)
+ (Classification._compile_classification)
+ (Classification._clear_compiled_classification): New. Methods to
+ manage a 'compiled' representation of the classification groups
+ which is created on demand
+ (Classification.InsertGroup, Classification.RemoveGroup)
+ (Classification.ReplaceGroup): reset the compiled representation
+ (Classification.FindGroup): Use the compiled representation to
+ find the matching group
+ (ClassGroupRange.GetRangeTuple): New. Return the range as a tuple
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/classification.py (Classification.SetDefaultGroup):
+ Send a CLASS_CHANGED message
+ (Classification.RemoveGroup): Send a CLASS_CHANGED message and do
+ not return the removed group since it wasn't used.
+
+ * test/test_classification.py
+ (TestClassification.test_set_default_group): New. Test the
+ SetDefaultGroup method
+ (TestClassification.test_insert_group): New. Test the InsertGroup
+ method
+ (TestClassification.test_remove_group): New. Test the RemoveGroup
+ method
+ (TestClassification.test_replace_group): New. Test the
+ ReplaceGroup method
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_classification.py (TestClassification.setUp):
+ Subscribe to the CLASS_CHANGED messages
+ (TestClassification.tearDown): New. Destroy the classification
+ properly
+ (TestClassification.test_defaults): Add tests for the default line
+ width and whether no messages were sent yet
+ (TestClassification.test_set_default_properties): Add tests for
+ messages and setting the default line width
+ (TestClassification.test_add_singleton)
+ (TestClassification.test_add_range)
+ (TestClassification.test_multiple_groups): Add tests for messages
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ Some more refactoring in preparation for new tests:
+
+ * test/test_classification.py (TestClassification.setUp): New.
+ Instantiate the classification here. Update the test methods
+ accordingly.
+ (TestClassification.test_multiple_groups): Make sure that the two
+ singletons matching 1 are considered different.
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_classification.py (red, green, blue): New. These
+ constants were used in several cases. Update the relevant methods.
+ (TestClassification.test_defaults)
+ (TestClassification.test_set_default_properties)
+ (TestClassification.test_add_singleton)
+ (TestClassification.test_add_range)
+ (TestClassification.test_multiple_groups)
+ (TestClassification.test_deepcopy): New. These were formerly all
+ part of the single method test.
+ (TestClassification.test_deepcopy): Removed.
+ (TestClassIterator): Removed. The test case is now a method of
+ TestClassification since it tests part of the public interface of
+ Classification
+ (TestClassification.test_iterator): New. Used to be
+ TestClassIterator effectively
+
+2003-10-31 Jan-Oliver Wagner <jan at intevation.de>
+
+ GUIfied the functions of the profiling extension.
+
+ * /Extensions/profiling/__init__.py: New: Init to make this
+ directory a package.
+
+ * Extensions/profiling/profiling.py: Moved menu entries to
+ the Extensions menu. Applied _() for strings.
+ (profile_screen_renderer): Catch the detailed printout and present
+ it in a dialog.
+ (time_screen_renderer): Raise a dialog to present the result instead
+ of printing it to stdout.
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_classification.py (TestClassGroupProperties)
+ (TestClassGroup, TestClassGroupDefault, TestClassGroupRange)
+ (TestClassGroupSingleton, TestClassIterator, TestClassification):
+ Split TestClassification into several classes, one for each class
+ being tested. TestClassification itself now only tests
+ Classification. This split makes changes to the tests a bit easier
+
+2003-10-31 Bernhard Herzog <bh at intevation.de>
+
+ * Extensions/profiling/profiling.py: New. Extension to measure
+ Thuban performance
+
+2003-10-31 Frank Koormann <frank at intevation.de>
+
+ Added two items to legend popup menu: Remove Layer and Show Layer Table
+
+ * Thuban/UI/legend.py (LegendPanel._OnRemoveLayer,
+ LegendPanel._OnShowTable): New event handlers, call the corresponding
+ mainwindow methods.
+ (LegendTree._OnRightClick): Added items to popup menu.
+
+2003-10-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/dialogs.py (ThubanFrame.__init__): Handle
+ EVT_WINDOW_DESTROY
+ (ThubanFrame.OnDestroy): New. Handler for EVT_WINDOW_DESTROY. Does
+ nothing but is convenient for the derived classes.
+
+ * Thuban/UI/tableview.py
+ (TableFrame.OnDestroy, LayerTableFrame.OnDestroy): New.
+ Unsubscribe the messages here not in OnClose because that might
+ get called multiple times. Fixes RT #2196
+ (TableFrame.OnClose, LayerTableFrame.OnClose): Removed. Not needed
+ anymore.
+
+ * README: Update the minimum requirement for wxPython. Since we
+ now use the EVT_WINDOW_DESTROY event, we need at least 2.4.0.4,
+ the version in which that was introduced for all platforms
+
+2003-10-30 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.OnJoin): Wrapped the major parts of
+ the join process in a ThubanBeginBusyCursor, ThubanEndBusyCursor
+ frame.
+
+2003-10-30 Jan-Oliver Wagner <jan at intevation.de>
+
+ Improved APR import extension, added further EPSG definitions
+ and some cleanup regarding string class.
+
+ * test/test_proj.py (TestProjection.test_get_projection_units_geo):
+ Added test for alias 'longlat'.
+
+ * Resources/Projections/epsg-deprecated.proj: New. Contains
+ deprecated EPSG definitions.
+
+ * Extensions/importAPR/odb.py (ODBBaseObject.TreeInfo): Added
+ the variable names for objects.
+
+ * Extensions/importAPR/apr.py (APR_BLnSym, APR_BMkSym, APR_BShSym): New.
+ Copied from importAPR and provided with documentation.
+
+ * Extensions/importAPR/importAPR.py (APR_BLnSym, APR_BMkSym, APR_BShSym):
+ Moved to apr.py.
+ (APR_View): Added object ref 'ITheme'.
+
+ * Thuban/Lib/fileutil.py, Thuban/UI/proj4dialog.py: Replaced string
+ split function by corresponding use of the string class method.
+
+ * Thuban/Model/xmlwriter.py: Replaced string replace function by
+ corresponding string method.
+
+2003-10-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/baserenderer.py
+ (BaseRenderer.draw_shape_layer_incrementally): Speed up the
+ special case of a classification that only has the default group
+
+2003-10-27 Bernhard Herzog <bh at intevation.de>
+
+ * po/fr.po, po/es.po: Updated translations from Daniel Calvelo
+
+ * po/de.po: Update.
+
+ * Thuban/UI/application.py
+ (ThubanApplication.ShowExceptionDialog): Handle translation of the
+ dialog message properly
+
+2003-10-27 Bernhard Herzog <bh at intevation.de>
+
+ Rework how localization works so that we use wx's translation
+ functions when running Thuban as a normal application but not when
+ we don't need any UI, such as in the test suite. See the comment
+ in Thuban/__init__.py for details
+
+ * Thuban/__init__.py (_): Add one level of indirection to make the
+ translation handling more flexible and to make it possible to use
+ either wx's translation services or not.
+ (gettext_identity, translation_function_installed)
+ (install_translation_function): New function to help with this
+
+ * Thuban/UI/__init__.py: Install the wx specific translation
+ function if it's OK to do that
+
+ * test/support.py (initthuban): Install a dummy translation
+ function so that importing Thuban.UI doesn't install a wx specific
+ one for which would need to import wxPython
+
+2003-10-27 Bernhard Herzog <bh at intevation.de>
+
+ * HOWTO-Release: Source archives should be created first and the
+ binary packages should be created from the source archives.
+ There's an official debian package now so there's no need to test
+ the rpm on debian anymore
+
+2003-10-27 Bernhard Herzog <bh at intevation.de>
+
+ Several rendering changes:
+
+ - Render the selection into a separate bitmap so that only that
+ bitmap needs to be redrawn when the selection changes
+
+ - Render incrementally showing previews and allowing interaction
+ before rendering is complete
+
+ - Update the renderer interface a bit. Most parameters of
+ RenderMap are now parameters of the constructor
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.__init__): Add the map
+ and the update region as parameters. Update the doc-string
+ (BaseRenderer.render_map_incrementally): New. Generator function
+ to renders the map incrementally
+ (BaseRenderer.render_map): Remove the map argument (it's now in
+ the constructor) and simply iterate over the
+ render_map_incrementally generator to draw the map.
+ (BaseRenderer.draw_shape_layer_incrementally)
+ (BaseRenderer.draw_shape_layer): Renamed to
+ draw_shape_layer_incrementally and changed into a generator that
+ yields True every 500 shapes. Used by render_map_incrementally to
+ render shape layers incrementally
+
+ * Thuban/UI/renderer.py (ScreenRenderer.RenderMap): Removed the
+ map and region parameters which are now in the constructor
+ (ScreenRenderer.RenderMapIncrementally): New. Public frontend for
+ the inherited render_map_incrementally.
+ (BaseRenderer.draw_shape_layer): Removed.
+ (ScreenRenderer.draw_selection_incrementally): New. The selection
+ drawing part of the removed draw_shape_layer as a generator
+ (ScreenRenderer.layer_shapes): Update because of the region
+ parameter change
+ (ExportRenderer.__init__): New. Extend the inherited constructor
+ with the destination region for the drawing
+ (ExportRenderer.RenderMap): Removed the map and region parameters
+ which are now in the constructor
+
+ * Thuban/UI/view.py (MapCanvas.PreviewBitmap): New. Return a
+ bitmap suitable for a preview in a tool
+ (CanvasPanTool.MouseMove): Use the PreviewBitmap method to get the
+ bitmap
+ (MapPrintout.draw_on_dc): Adapt to new renderer interface
+ (MapCanvas.OnPaint): Handle drawing the selection bitmap if it
+ exists
+ (MapCanvas.OnIdle): Update the logic to deal with incremental
+ rendering and the selection bitmap
+ (MapCanvas._do_redraw): Handle the instantiation of the render
+ iterator and the redraws during rendering
+ (MapCanvas._render_iterator): New. Generator to incrementally
+ redraw both bitmaps
+ (MapCanvas.Export): Adapt to new renderer interface.
+ (MapCanvas.full_redraw): Reset the selection bitmap and the
+ renderer iterator too
+ (MapCanvas.redraw_selection): New. Force a redraw of the selection
+ bitmap
+ (MapCanvas.shape_selected): Only redraw the selection bitmap
+
+ * test/test_baserenderer.py
+ (TestBaseRenderer.test_polygon_no_projection)
+ (TestBaseRenderer.test_raster_no_projection)
+ (TestBaseRenderer.test_point_map_projection)
+ (TestBaseRenderer.test_point_layer_and_map_projection)
+ (TestBaseRenderer.test_point_layer_projection)
+ (TestBaseRenderer.test_point_with_classification): Adapt to new
+ renderer interface
+
+2003-10-24 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/thuban/wxproj.cpp (draw_polygon_shape)
+ (point_in_polygon_shape, shape_centroid): Raise an exception if
+ the shape can't be read. Previously invalid shape ids would lead
+ to a segfault.
+
+ * test/test_wxproj.py (TestShapeCentroid.test_invalid_shape_id):
+ New. test whether an exception is raised for invalid shape ids
+
+2003-10-24 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/proj.py (Projection.GetProjectedUnits): Added 'longlat'
+ as alias for 'latlong'.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__): Added 'longlat'
+ as alias for 'latlong'.
+
+2003-10-24 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.proj_selection_changed): Set
+ the projection even for the UnknownPanel.
+ (UnknownProjPanel.__init__): Define the text and create the textctrl
+ widget.
+ (UnknownProjPanel._DoLayout): Replaced static text widget by the
+ textctrl created in __init__.
+ (UnknownProjPanel.SetProjection): Set the text for the text ctrl
+ including the parameters of the projection.
+
+2003-10-24 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Resources/Projections/epsg.proj: New. This is a list of
+ EPSG codes with parameters for proj. The list has been
+ generated using devtools/create_epsg.py based on the
+ file nad/epsg of the proj 4.4.7 package. Four projection
+ definitions have been deleted as they are not accepted by proj:
+ "CH1903+ / LV95", "Bern 1898 (Bern) / LV03C", "CH1903 / LV03"
+ and "HD72 / EOV".
+
+2003-10-22 Bernhard Herzog <bh at intevation.de>
+
+ Some more tweaks to the projection dialog which should fix RT
+ #1886.
+
+ * Thuban/UI/projlist.py (ProjectionList.Destroy): Unsubscribe from
+ the ProjFile's messages and call the base class methods correctly
+ (ProjectionList.SelectProjection): Set the wxLIST_STATE_FOCUSED
+ flag on the newly selected item too. Otherwise some other item is
+ focused and the first time the focus is moved with the keyboard
+ the selection moves in unexpected ways.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__): Do not set the
+ focus on the OK button, only on the projection list. That way the
+ list really has the focus initially
+ (ProjFrame.OnClose): Call the projection list's Destroy method to
+ make it unsubscribe all messages
+
+2003-10-21 Bernhard Herzog <bh at intevation.de>
+
+ Rework the projection dialog to fix a few bugs, including RT 2166
+ and most of 2168
+
+ * Thuban/UI/projlist.py: New. The class ProjectionList is a
+ special wxListCtrl to show a list of projections in a more MVC
+ fashion
+
+ * Thuban/UI/projdialog.py (ProjFrame): Substantial changes
+ throughout the class. The main change is to use the ProjectionList
+ class instead of a normal wxListBox. Also, add an explicit
+ "Unknown" projection to the projection choice control.
+ (ProjPanel.__init__): Add an "unknown" ellipsoid
+ (TMPanel.__init__, LCCPanel.__init__): Tweak the order of
+ instantiation of the panel's controls to make the tab-order more
+ natural
+
+2003-10-21 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_load.py (TestSingleLayer.file_contents)
+ (TestSingleLayer.test): Add non-ascii characters to the titles of
+ session, map and layer. This is effectively a port of the
+ TestUnicodeStrings test in test_load_0_8.py which for some reason
+ was only added there.
+
+ * test/test_load_0_9.py (TestSingleLayer.file_contents)
+ (TestSingleLayer.test): Same as in test_load.py: add non-ascii
+ characters to the titles of session, map and layer,.
+
+2003-10-21 Bernhard Herzog <bh at intevation.de>
+
+ Add EPSG projection handling to .thuban files
+
+ * test/test_save.py (SaveSessionTest.dtd)
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table)
+ (SaveSessionTest.test_save_postgis): Update to 1.0-dev namespace
+ (SaveSessionTest.testSingleLayer): Update to 1.0-dev namespace and
+ use a and epsg projection to test saving them
+
+ * test/test_load.py (LoadSessionTest.dtd): Update to 1.0-dev
+ namespace
+ (TestLayerVisibility.file_contents, TestLabels.file_contents)
+ (TestLayerProjection.file_contents)
+ (TestRasterLayer.file_contents, TestJoinedTable.file_contents)
+ (TestPostGISLayer.file_contents)
+ (TestPostGISLayerPassword.file_contents)
+ (TestLoadError.file_contents, TestLoadError.test): Update to use
+ 1.0-dev namespace
+ (TestSingleLayer.file_contents, TestSingleLayer.test): Update to
+ use 1.0-dev namespace and use an EPSG projection to test whether
+ loading it works
+
+ * test/test_load_0_9.py: New. Effectively a copy of test_load.py
+ as of Thuban 0.9. These are now tests to determine whether Thuban
+ can still read files generated by Thuban 0.9
+
+ * Thuban/Model/save.py (SessionSaver.write)
+ (SessionSaver.write_session): Use the 1.0 dtd and 1.0-dev
+ namespace
+ (SessionSaver.write_projection): Write the projection's epsg
+ attribute
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Also accept the
+ thuban-1.0-dev.dtd namespace
+ (SessionLoader.check_attrs): Allow a callable object as conversion
+ too
+ (SessionLoader.start_projection, SessionLoader.end_projection)
+ (SessionLoader.start_parameter): Handle the epsg attribute and
+ rename a few instance variables to lower case
+
+ * Resources/XML/thuban-1.0.dtd: New. Only difference to
+ thuban-0.9.dtd is the epsg attribute for projections.
+
+2003-10-21 Bernhard Herzog <bh at intevation.de>
+
+ * test/runtests.py (main): Let the user specify which tests to run
+ on the command line
+
+ * test/support.py (ThubanTestResult.getDescription): Override to
+ give a better short description. The description can be used as a
+ parameter to run_tests to run that particular test in isolation.
+
+2003-10-21 Frank Koormann <frank at intevation.de>
+
+ Popup menu for legend. Scheduled for the 1.2 release this was too
+ simple to implement: The popup menu is bound to the legend tree, while
+ the events are hanlded by its anchestor, the legend panel. This
+ allows reuse of all the event handlers already implemented for the
+ legend toolbar buttons.
+
+ * Thuban/UI/legend.py (LegendPanel.__init__): EVT_MENU macros
+ to add handlers for the events issued by the popup menu.
+ (LegendPanel._OnToggleVisibility): Handler for toggling layer
+ visibility event
+ (LegendPanel._OnProjection): Handler for layer projection event.
+ (LegendTree.__init__): Added EVT_TREE_ITEM_RIGHT_CLICK
+ (LegendTree._OnRightClick): Event handler for right click, select item
+ and pop up menu.
+ (LegendTree.ToggleVisibility): Toggle layer visibility
+ (LegendTree.LayerProjection): Raise layer projection dialog for
+ current layer.
+
+2003-10-21 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/Projections/defaults.proj: Use correct DOCTYPE
+ declaration. The top-level element is projectionlist not projfile
+
+2003-10-20 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.write_proj_file): New. helper
+ method to write a projfile and display a busy cursor and error
+ dialogs.
+ (ProjFrame._OnSave, ProjFrame._OnAddToList, ProjFrame._OnImport)
+ (ProjFrame._OnExport, ProjFrame._OnRemove): Use write_proj_file
+ (ProjFrame.__FillAvailList): Translate "<None>" too and display a
+ busy cursor while loading the user and system prj files.
+
+2003-10-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/resource.py (projfile_cache): Introduce a cache for
+ ProjFile objects
+ (clear_proj_file_cache): New function to clear the cache. Mainly
+ useful for use by the test suite
+ (read_proj_file): Use the cache.
+
+ * test/test_proj.py (TestProjFile): Clarify the doc-string
+ (ProjFileReadTests): Update doc-string
+ (ProjFileReadTests.test_get_system_proj_file): Check whether the
+ system proj files is cached.
+ (ProjFileLoadTestCase): New base class for the proj file tests
+ derived from support.FileLoadTestCase to provide some common
+ behavior.
+ (TestLoadingProjFile)
+ (TestLoadingProjFileWithEmptyProjectionlist.file_contents)
+ (TestProjFileWithInvalidParameters.file_contents): Derive from
+ ProjFileLoadTestCase
+ (TestLoadingProjFile.test_caching): New. Test whether the cache
+ works
+
+2003-10-16 Silke Reimer <silke at intevation.de>
+
+ * debian/*: New directory with configuration files for building a thuban
+ deb-package.
+
+2003-10-14 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py: Execute support.run_tests when run as
+ __main__ so that missing unsubscribes are detected
+ (TestProjFile.tearDown): Destroy the proj_file properly
+
+2003-10-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/messages.py (PROJECTION_ADDED)
+ (PROJECTION_REPLACED, PROJECTION_REMOVED): New message types for
+ the ProjFile objects
+
+ * Thuban/Model/proj.py (ProjFile): Derive from Publisher so we can
+ easily send messages when the projections change
+ (ProjFile.Add, ProjFile.Remove, ProjFile.Replace): Issue messages
+ when the change was successful
+
+ * test/test_proj.py (TestProjFile.setUp): Subscribe to some of the
+ proj file messages
+ (TestProjFile.test_add_remove)
+ (TestProjFile.test_remove_non_existing)
+ (TestProjFile.test_replace)
+ (TestProjFile.test_replace_non_existing): Test whether the right
+ messages are sent
+
+2003-10-14 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py (TestProjFile.test): Refactor into several
+ tests
+ (TestProjFile.test_add_remove)
+ (TestProjFile.test_remove_non_existing)
+ (TestProjFile.test_replace)
+ (TestProjFile.test_replace_non_existing): Some of the new
+ individual test cases
+ (TestProjFileSimple): New class for the rest of the test cases
+ that came out of the refactoring
+ (ProjFileTest): Derive from xmlsupport.ValidationTest so that the
+ derived classes don't have to
+
+2003-10-13 Bernhard Herzog <bh at intevation.de>
+
+ Add an optional EPSG code to the projection objects and extend the
+ .proj file format accordingly.
+
+ * Resources/XML/projfile.dtd (element projection): Add epsg
+ attribute
+
+ * Thuban/Model/proj.py (Projection.__init__): New parameter and
+ instance variable epsg. Update doc-string
+ (Projection.EPSGCode, Projection.Label): New methods to provide
+ access to EPSG code and a label for use in dialogs
+
+ * Thuban/Model/resource.py (ProjFileReader.start_projection)
+ (ProjFileReader.end_projection, ProjFileSaver.write_projfile):
+ Handle the epsg code attribute when reading or writing proj files
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnSave)
+ (ProjFrame._OnAddToList, ProjFrame.__DoOnProjAvail)
+ (ProjFrame.__FillAvailList): Use the projection's Label method to
+ get the string for the list box
+
+ * test/test_proj.py (TestProjection.test_label)
+ (TestProjection.test_label_epsg)
+ (TestProjection.test_epsgcode_for_non_epsg_projection)
+ (TestProjection.test_epsgcode_for_real_epsg_projection): New tests
+ for the label and EPSGCode methods
+ (WriteProjFileTests.doTestWrite, WriteProjFileTests.test_write)
+ (WriteProjFileTests.test_write_empty_file): Create the ProjFile
+ objects in the test cases and put the expected contents into the
+ test case methods too. Update doTestWrite accordingly
+ (TestLoadingProjFile)
+ (TestLoadingProjFileWithEmptyProjectionlist): New classes with the
+ read tests from TestProjFile.
+ (TestProjFile.doTestRead, TestProjFile.testRead): Removed. These
+ tests are now in the new classes.
+ (sample_projfile, sample_projfile_data)
+ (sample_projfile2, sample_projfile_data2): Removed. Not used
+ anymore.
+ (TestProjFile.test_read_unreadable_file): No need to reset the
+ permissions at the end anymore since we use a unique filename
+
+2003-10-13 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py: Some more refactoring of the test cases
+ (ProjFileTest): New base class for the proj file tests.
+ (TestProjFile): Derive from ProjFileTest
+ (TestProjFile.test_read_unreadable_file)
+ (TestProjFile.test_read_empty_file, TestProjFile.doTestRead): Use
+ the new filename method to get a unique filename
+ (TestProjFile.doTestWrite, TestProjFile.testWrite): Removed.
+ (WriteProjFileTests): New class for proj file write tests.
+ Contains the write test that were in TestProjFile originally.
+
+2003-10-13 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py (TestProjFile.testRead)
+ (TestProjFile.test_read_non_existing_file)
+ (TestProjFile.test_read_unreadable_file)
+ (TestProjFile.test_read_empty_file): Split into several methods.
+
+2003-10-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/sizers.py: New file with custom sizers.
+
+ * Thuban/UI/projdialog.py (ProjFrame.build_dialog): Instantiate
+ all projection type specific panels and put them into a
+ NotebookLikeSizer. This way the dialog doesn't change its size
+ when a different projection is selected
+ (ProjFrame.__init__): Rename projection_panels
+ projection_panel_defs and reuse projection_panels for a list of
+ the instantiated panels.
+ (ProjFrame._show_proj_panel, ProjFrame.__DoOnProjAvail)
+ (ProjFrame.__DoOnProjChoice): Changes due to the new handling of
+ the panels
+ (UnknownProjPanel._DoLayout): Place the newlines in the message
+ differently to make the panel narrower.
+ (TMPanel._DoLayout): Layout the parameters in one column.
+
+2003-10-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.build_dialog): New method
+ that contains all the setup for the dialog's widgets, layout and
+ event handling.
+ (__): Call build_dialog to build the dialog.
+ (ProjFrame.__set_properties, ProjFrame.__do_layout): Removed.
+ Their functionality is now in build_dialog
+ (ProjFrame.__VerifyButtons, ProjFrame.__VerifyButtons)
+ (ProjFrame.__DoOnProjAvail, ProjFrame.__DoOnProjAvail)
+ (ProjFrame.__DoOnProjChoice): Small updates due to slightly
+ different widget names and hierarchy introduced with build_dialog.
+
+2003-10-10 Bernhard Herzog <bh at intevation.de>
+
+ * README: Fix typo.
+
+2003-10-09 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/proj.py (ProjFile.Add): Do not check whether the
+ projection is already in the list. This is *a lot* faster when
+ loading files with hundreds of projections since it saves a linear
+ search. OTOH this will allow adding the same projection to the
+ user.proj file multiple times in the projection dialog but we'll
+ deal with that later
+
+2003-10-09 Jan-Oliver Wagner <jan at intevation.de>
+
+ * devtools: New. Directory for developer tools that are not intended
+ for the regular user.
+
+ * devtools/create_epsg.py: New. Convert the epsg file of proj into
+ a python .proj file.
+
+2003-10-09 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py
+ (TestProjection.test_get_parameter_without_equals_sign): New. Test
+ whether GetParameter handles parameters without "=" sign correctly
+
+ * Thuban/Model/proj.py (Projection.GetParameter): Handle
+ parameters that do not contain a "=". Update the doc-string
+
+2003-10-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.__set_properties): Remove the
+ length limit on the projname text control
+
+2003-10-08 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py (TestProjection.test_get_projection_units_geo)
+ (TestProjection.test_get_projection_units_normal): New. Tests for
+ the Projection.GetProjectedUnits method
+
+2003-10-08 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/resource.py (get_user_proj_file): small bug-fix:
+ Added missing 'val' parameter.
+
+2003-10-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.__DoOnProjAvail): When the
+ projection type of the currently selected projection is not known,
+ i.e. there's no panel for it, use the UnknownProjPanel
+ (ProjFrame.__DoOnProjChoice, ProjFrame._show_proj_panel): Split
+ the actual replacing of the proj panel into the new method
+ _show_proj_panel.
+ (UnknownProjPanel): Add doc-string.
+ (UnknownProjPanel._DoLayout): Insert a newline into the text so
+ that the panel is not so wide.
+
+2003-10-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/resource.py (read_proj_file): Return the warnings
+ too. Update the doc-string
+ (get_proj_files): Removed. It wasn't used anywhere
+ (get_system_proj_files, get_system_proj_file): Rename to
+ get_system_proj_file and return the ProjFile object and not a list
+ of ProjFile objects. Update the callers.
+ (get_user_proj_files, get_user_proj_file): Rename to
+ get_user_proj_file return the ProjFile object and not a list of
+ ProjFile objects. Update the callers.
+ (ProjFileReader.__init__): New instance variable for the warnings.
+ Rename the __pf ivar to projfile. Update the methods referring to
+ __pf
+ (ProjFileReader.end_projection): Catch any errors raised when
+ instantiating the projection and record that as an error. The
+ projection will not be in the final ProjFile object.
+ (ProjFileReader.GetWarnings): New method to return the warnings.
+
+ * Thuban/UI/projdialog.py (ProjFrame.show_warnings): New method to
+ show the warnings from the projfile reader
+ (ProjFrame._OnImport): Deal with any warnings returned by
+ read_proj_file
+ (ProjFrame.__FillAvailList): Deal with any warnings returned by
+ get_system_proj_file or get_user_proj_file.
+
+ * test/test_proj.py (TestProjFile.doTestRead): Check the warnings.
+ (TestProjFileWithInvalidParameters.file_contents): New test cases
+ to test whether read_proj_file handles invalid projection
+ parameters correctly
+ (TestProjFile.test_get_system_proj_file): New. Simple test for
+ resource.get_system_proj_file
+
+2003-10-07 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_derivedshapestore.py
+ (TestDerivedShapeStoreExceptions.tearDown): Clear the session
+ properly so that the temporary directories get deleted correctly
+
+2003-10-06 Bernhard Herzog <bh at intevation.de>
+
+ Handle the title changes in a proper MVC way.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Subscribe to the
+ canvas' TITLE_CHANGED messages
+ (MainWindow.update_title): New. Update the main window's title
+ (MainWindow.__SetTitle): Removed. Use update_title instead.
+ (MainWindow.SetMap): Use update_title instead of __SetTitle
+ (MainWindow.RenameMap): Do change the window title explicitly
+ here. That's handled in a proper MVC way now.
+ (MainWindow.title_changed): New. Subscriber for the TITLE_CHANGED
+ messages
+
+ * Thuban/Lib/connector.py (Conduit): New class to help classes
+ that forward messages
+
+ * Thuban/UI/viewport.py: Forward the map's TITLE_CHANGED messages
+ (ViewPort): Derive from Conduit instead of Publisher
+ (ViewPort.Subscribe, ViewPort.Unsubscribe): Use the new base class
+ when calling the inherited versions
+ (ViewPort._subscribe_map, ViewPort._unsubscribe_map): New helper
+ methods to subscribe and unsubscribe map messages
+ (ViewPort.SetMap, ViewPort.Destroy): Use the new helper methods to
+ handle the map subscriptions
+ (ViewPort.Map, ViewPort.map_projection_changed)
+ (ViewPort.layer_projection_changed): Add or update doc-strings
+
+ * test/test_connector.py (TestPublisher.test_issue_simple): Fix
+ typo
+ (MyConduit): Helper class for the Conduit test.
+ (TestConduit): Test cases for Conduit
+
+ * test/test_connector.py: Use support.run_tests as main.
+
+ * test/test_viewport.py (ViewPortTest.setUp): Also subscribe to
+ the TITLE_CHANGED messages
+ (ViewPortTest.test_forwarding_title_changed): New test to check
+ whether the viewport forwards the map's TITLE_CHANGED messages
+ (TestViewportWithPostGIS.tearDown): Call the map's Destroy method
+ after the port's because the latter may require a still functional
+ map.
+
+2003-10-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.maps_changed): Add
+ doc-string
+
+2003-10-06 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py (ViewPortTest.setUp)
+ (SimpleViewPortTest.test_init_with_size): Move the test for the
+ initial size as a constructor parameter from ViewPortTest.setUp
+ method to a new separate test in SimpleViewPortTest.
+
+2003-10-06 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py (MockView): New class derived from
+ ViewPort with a mock implementation of GetTextExtent to be used in
+ the test cases
+ (ViewPortTest.setUp): Use MockView instead of ViewPort
+
+ * Thuban/UI/viewport.py (ViewPort.GetTextExtent): Turn this method
+ into what would be a "pure virtual function" in C++: always raise
+ NotImplementedError. Mock implementations for test cases don't
+ belong into the real code
+
+2003-10-02 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_layer.py (TestLayer.test_empty_layer): Explicitly
+ close the dbf file we create so that it's contents have been
+ written properly.
+
+ * libraries/shapelib/shptree.c, libraries/shapelib/shpopen.c,
+ libraries/shapelib/shapefil.h, libraries/shapelib/dbfopen.c:
+ Update to shapelib 1.2.10
+
+2003-10-01 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/tree.py, Thuban/UI/main.py: Remove the #! line as
+ it annoys lintian which warns about these files not being
+ executable. The #! isn't necessary here since if you absolutely
+ must execute them you can always say "python <filename>".
+
+2003-09-26 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/classgen.py (GenQuantiles0): Removed since it's
+ only used in GREAT-ER but not used in Thuban itself. When GREAT-ER
+ is ported to a newer the import will fail, so it should be noticed
+ immediately that this function is gone.
+ Fixes RT#1919
+
+2003-09-26 Bernhard Herzog <bh at intevation.de>
+
+ Add a DTD for the projection files and make thuban write valid
+ projection files
+
+ * Resources/XML/projfile.dtd: New. DTD for thuban's projection
+ files
+
+ * Thuban/Model/resource.py (ProjFileSaver.write): Use
+ 'projectionlist' as the name in the document type declaration so
+ that it matches the element type of the root element.
+
+ * test/test_proj.py (sample_projfile, sample_projfile2): Use
+ 'projectionlist' as the name in the document type declaration just
+ as it is done now in the files thuban would write
+ (sample_projfile, sample_projfile_data): Fix spelling of
+ "Mercator"
+ (TestProjFile.doTestWrite): Validate the written and the expected
+ XML data
+ (TestProjFile): Derive from ValidationTest so that we can run xml
+ validation tests
+
+2003-09-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/renderer.py (ExportRenderer.render_legend): Do not
+ modify the list returned by map.Layers() in place since it is the
+ actual list of layers used by the map.
+
+2003-09-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added subsection to chapter
+ Extensions to describe the extensions coming with the Thuban
+ standard package (gns2shp and importAPR).
+
+2003-09-23 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/thuban/wxproj.cpp (project_point): if there's an
+ inverse but no forward projection, convert to degrees after
+ applying the inverse projection. Fixes RT#2096
+
+ * test/test_wxproj.py: New. Test cases for wxproj.so. One test
+ implicitly tests for the fix to RT#2096
+
+ * test/support.py (FloatComparisonMixin.assertFloatSeqEqual):
+ Check that the sequences have the same lengths
+
+ * Resources/Projections/defaults.proj (Geographic projection): Use
+ a much more precise value for the to_meter attribute.
+
+2003-09-22 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (initthuban): Make sure to unset the LANG env.
+ var. so that tests that compare translated strings work. Solves RT
+ #2094
+
+2003-09-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ Small improvement of APR import.
+
+ * Extensions/importAPR/test/test_apr.py (aprTest.test_LClass):
+ Added tests for text-ranges.
+
+ * Extensions/importAPR/apr.py (APR_LClass.GetThubanRange): Now
+ returns a string object if the range is based on text.
+
+ * Extensions/importAPR/importAPR.py (import_apr_dialog): Unified
+ range retrieval.
+
+2003-09-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ Initial version of the importAPR extension which is in
+ experimental state.
+
+ * /Extensions/importAPR/, /Extensions/importAPR/samples/,
+ /Extensions/importAPR/test/: New directories.
+
+ * /Extensions/importAPR/samples/README: New: Howto load the samples.
+
+ * /Extensions/importAPR/samples/iceland.apr: New: A sample APR
+ file which refers to the Thuban Iceland demo data.
+
+ * /Extensions/importAPR/test/README: New: Howto execute the tests.
+
+ * /Extensions/importAPR/test/test_apr.py: New: Tests for APR classes.
+
+ * /Extensions/importAPR/apr.py: New: Classes for ArcView Objects
+ as in '.apr'-files.
+
+ * /Extensions/importAPR/odb.py: New: Classes for generic ArcView
+ ODB Objects as in '.apr', '.avl' and other files.
+
+ * /Extensions/importAPR/__init__.py: New: Init to make this
+ directory a package.
+
+ * /Extensions/importAPR/importAPR.py: New: Import a ArcView
+ project file (.apr) and convert it to Thuban.
+
+2003-09-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Extensions/gns2shp.gns2shp.py: The main module of gns2shp.
+
+2003-09-19 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Extended section 'Installation'
+ with description on RPM installation and RPM binary package
+ creation.
+
+2003-09-18 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (data_files): Only add the mo files if the Locales
+ directory actually exists, so that setup.py works with a fresh CVS
+ checkout
+
+2003-09-12 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Examples/simple_extensions/simple_tool.py: bugfix: Tool is now
+ in viewport, not anymore in view
+
+2003-09-04 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introducing first Extension (gns2shp).
+
+ * Extensions, Extensions/gns2shp, Extensions/gns2shp/test: New.
+
+ * Extensions/__init__.py: New. init to make this dir a package.
+
+ * Extensions/gns2shp/__init__.py: New. init to make this dir a package.
+
+ * Extensions/gns2shp/test/README: New. some info on this test directory.
+
+ * Extensions/gns2shp/test/ls.txt: New. test data set (Liechtenstein).
+
+ * Extensions/gns2shp/test/test_gns2shp.py: New. Test for correct creation
+ of Shapefile from GNS text file format
+
+2003-09-03 Jan-Oliver Wagner <jan at intevation.de>
+
+ Fix/workaround for bug #2019:
+ https://intevation.de/rt/webrt?serial_num=2019
+
+ * Thuban/UI/identifyview.py (IdentifyView.ID_STOP): New.
+ (IdentifyView.__init__): Added another button that allows to
+ stop the identify mode.
+ (IdentifyView.OnStop): New. Stops the identify mode.
+
+2003-09-03 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introducing a new exception dialog that allows to exit the
+ application immediately.
+ This fixes bug #2060: https://intevation.de/rt/webrt?serial_num=2060
+
+ * Thuban/UI/exceptiondialog.py: New. A special exception dialog.
+
+ * Thuban/UI/application.py (ThubanApplication.ShowExceptionDialog):
+ Made strings available to translations. Exchanged the simple
+ ScrolledMessageDialog by the new ExceptionDialog.
+
+2003-09-01 Bernhard Herzog <bh at intevation.de>
+
+ * NEWS: New. Summary of changes and release notes.
+
+ * MANIFEST.in: Add NEWS
+
+2003-09-01 Bernhard Herzog <bh at intevation.de>
+
+ * MANIFEST.in: Correct the include statement for the mo-files and
+ include the documentation too.
+
+ * setup.py (data_files): Add the .mo files
+ (setup call): Up to version 0.9.0
+
+2003-09-01 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/dbdialog.py (ChooseDBTableDialog.__init__): Change the
+ parameter list to just parent and session
+ (ChooseDBTableDialog.__set_properties): Removed. Setting the
+ selection of empty list boxes is not allowed (and produces C++
+ assertion errors) and the rest of the setup is better done in
+ __init__ anyway.
+ (ChooseDBTableDialog.OnCancel, ChooseDBTableDialog.OnOK)
+ (ChooseDBTableDialog.OnLBDClick, DBDialog.OnOK): Use the Python
+ builtins True/False for booleans to avoid warnings from wxPython
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddDBLayer): Adapt to new
+ ChooseDBTableDialog constructor parameters.
+
+2003-09-01 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py
+ (PostGISTable): Extend doc-string
+ (PostGISTable._fetch_table_information): Set the column index
+ correctly, pretending ignored columns don't exist.
+
+ * test/test_postgis_db.py (TestPostGISIgnoredColumns): New tests
+ for postgis tables with data types not yet supported by thuban.
+
+2003-08-29 Bernhard Herzog <bh at intevation.de>
+
+ * HOWTO-Release: Tweak item about running the tests.
+
+2003-08-29 Jan-Oliver Wagner <jan at intevation.de>
+
+ * /Doc/manual/thuban-manual.xml: updated to version 1.0pre2.
+
+2003-08-29 Bernhard Herzog <bh at intevation.de>
+
+ Add some missing parameters to projections. Proj complains about
+ them on windows but for some reason not on Linux.
+
+ * test/test_save.py (SaveSessionTest.testLayerProjection): Add
+ missing required projection parameters
+
+ * test/test_proj.py (TestProjFile.test): Add missing required
+ projection parameters
+
+ * test/test_load_0_8.py (TestLayerProjection.file_contents)
+ (TestLayerProjection.test): Add missing required projection
+ parameters and tests for them
+
+ * test/test_load.py (TestLayerProjection.file_contents)
+ (TestLayerProjection.test): Add missing required projection
+ parameters and tests for them
+
+ * test/test_layer.py (TestLayer.test_base_layer): Add missing
+ required projection parameters
+
+2003-08-29 Bernhard Herzog <bh at intevation.de>
+
+ * libraries/pyprojection/Projection.i: Use pj_get_errno_ref to
+ access the pj_errno because directly accessing pj_errno doesn't
+ work on windows if the proj library is in a DLL
+
+ * libraries/pyprojection/Projection_wrap.c: Update from Projection.i
+
+2003-08-28 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_proj.py: Import things from Thuban after calling
+ initthuban
+
+ * test/test_load.py (LoadSessionTest.filenames): New class
+ variable with the filename attributes to normalize
+ (LoadSessionTest.check_format): Pass self.filenames to
+ sax_eventlist to normalize the filename attributes
+
+ * test/xmlsupport.py: Add cvs keywords
+ (SaxEventLister.__init__): New parameter filenames which indicates
+ attributes that contain filenames
+ (SaxEventLister.startElementNS): Normalize the filename attributes
+ with os.path.normpath
+ (sax_eventlist): New parameter filenames to pass through to
+ SaxEventLister
+
+ * test/test_derivedshapestore.py: Make this file callable as a
+ program to execute the tests
+ (TestDerivedShapeStoreExceptions.test_table_with_wrong_size): Bind
+ the session to self.session so that it gets destroyed properly
+
+ * test/test_layer.py (TestLayer.tearDown): Call the session's
+ Destroy method
+
+ * test/test_map.py (TestMapBase.tearDown): Destroy self.session
+ too if it exists
+ (TestMapAddLayer.test_add_layer): Bind the session to self.session
+ so that it gets destroyed properly
+
+ * test/postgissupport.py (reason_for_not_running_tests): Add a
+ test for the existence of popen2.Popen4.
+
+ * test/test_save.py (SaveSessionTest.tearDown): New. Provide a
+ reliable way to destroy the sessions created in the test cases
+ (SaveSessionTest.test_dbf_table): Bind the session to self.session
+ so that it gets destroyed properly
+ (SaveSessionTest.testLayerProjection): Bind the session to
+ self.session so that it gets destroyed properly
+
+ * test/test_session.py (UnreferencedTablesTests.tearDown): Make
+ sure that the session is destroyed properly
+
+ * test/test_shapefilestore.py: Make this callable as a program to
+ execute the tests
+
+ * test/test_scalebar.py: Remove unnecessary import of _ from
+ Thuban
+
+ * test/support.py (print_garbage_information): Call initthuban
+ here because it may be called indirectly from test cases that test
+ test support modules which do not use anything from thuban itself
+ (ThubanTestProgram.runTests): Remove unnecessary debug print
+
+2003-08-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/version.py (longversion): Update to 0.9
+
+ * Thuban/UI/mainwindow.py: Remove some unused imports
+
+ * README: Add section about required additional software. Add date
+ and revision CVS keywords
+
+ * HOWTO-Release: Add item about the translations. Add date and
+ revision CVs keywords and change formatting to match README a bit
+ better
+
+ * po/de.po: Update for 0.9
+
+ * test/README: Tweak the wording a little because many tests are
+ not really unittest.
+
+2003-08-27 Bernhard Herzog <bh at intevation.de>
+
+ As preparation for the 0.9 release, switch thuban files to a
+ non-dev namespace
+
+ * Thuban/Model/save.py (SessionSaver.write_session): Write files
+ with the http://thuban.intevation.org/dtds/thuban-0.9.dtd
+ namespace
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Accept the
+ http://thuban.intevation.org/dtds/thuban-0.9.dtd namespace too
+
+ * test/test_save.py (SaveSessionTest.dtd)
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table)
+ (SaveSessionTest.test_save_postgis): Update for new namespace
+
+ * test/test_load.py (LoadSessionTest.dtd, TestSingleLayer)
+ (TestLayerVisibility.file_contents, TestLabels.file_contents)
+ (TestLayerProjection.file_contents)
+ (TestRasterLayer.file_contents, TestJoinedTable.file_contents)
+ (TestPostGISLayer.file_contents)
+ (TestPostGISLayerPassword.file_contents)
+ (TestLoadError.file_contents, TestLoadError.test): Update for new
+ namespace
+
+2003-08-27 Bernhard Herzog <bh at intevation.de>
+
+ Make the table interface distinguish between row ids (an integer
+ that uniquely identifies a row) and row ordinals (a simple row
+ count from 0 to NumRows() - 1)
+
+ * Thuban/Model/postgisdb.py (PostGISTable.RowIdToOrdinal)
+ (PostGISTable.RowOrdinalToId): New methods to conver between row
+ ids and row ordinals
+ (PostGISTable.ReadRowAsDict, PostGISTable.ReadValue): New keyword
+ parameter row_is_ordinal to indicate whether the row parameter is
+ the row id or the ordinal
+
+ * Thuban/Model/transientdb.py (TransientTableBase.RowIdToOrdinal)
+ (TransientTableBase.RowOrdinalToId)
+ (AutoTransientTable.RowIdToOrdinal)
+ (AutoTransientTable.RowOrdinalToId): Same new methods as in
+ PostGISTable.
+ (TransientTableBase.ReadRowAsDict, TransientTableBase.ReadValue)
+ (AutoTransientTable.ReadRowAsDict, AutoTransientTable.ReadValue):
+ Same new parameter as in PostGISTable.
+
+ * Thuban/Model/table.py (DBFTable.RowIdToOrdinal)
+ (DBFTable.RowOrdinalToId, MemoryTable.RowIdToOrdinal)
+ (MemoryTable.RowOrdinalToId): Same new methods as in PostGISTable.
+ (DBFTable.ReadValue, DBFTable.ReadRowAsDict)
+ (MemoryTable.ReadValue, MemoryTable.ReadRowAsDict): Same new
+ parameter as in PostGISTable.
+
+ * Thuban/UI/tableview.py (DataTable.RowIdToOrdinal)
+ (DataTable.RowOrdinalToId): New methods to convert between row ids
+ and row ordinals.
+ (TableGrid.SelectRowById): New method to select a row based on its
+ ID as opposed to its ordinal
+ (DataTable.GetValue, TableGrid.OnRangeSelect)
+ (TableGrid.OnSelectCell, LayerTableGrid.select_shapes)
+ (QueryTableFrame.OnQuery, QueryTableFrame.get_selected)
+ (LayerTableFrame.__init__): Convert between row ids and row
+ ordinals as appropriate
+
+ * test/postgissupport.py (PostGISDatabase.__init__): Add
+ doc-string.
+ (PostGISDatabase.initdb): The optional third item in a tuple in
+ tables is now a (key, value) list with additional arguments to
+ pass to upload_shapefile
+ (upload_shapefile): New parameter gid_offset to allow gids that
+ are not the same as the shapeids in the shapefile
+ (PostgreSQLServer.get_default_static_data_db): Use the new
+ gid_offset to make the gids in landmarks 1000 higher than the
+ shapeids in the shapefile
+
+ * test/test_viewport.py
+ (TestViewportWithPostGIS.test_find_shape_at_point): Adapt to the
+ new shapeids in the landmarks table
+
+ * test/test_transientdb.py
+ (TestTransientTable.run_iceland_political_tests)
+ (TestTransientTable.test_transient_joined_table): Add tests for
+ the new table methods and new keywords arguments.
+
+ * test/test_postgis_db.py
+ (TestPostGISTable.test_read_row_as_dict_row_count_mode)
+ (TestPostGISTable.test_read_value_row_count_mode)
+ (TestPostGISTable.test_row_id_to_ordinal)
+ (TestPostGISTable.test_row_oridnal_to_id): New test for the new
+ table methods and the new arguments
+ (TestPostGISShapestorePoint.test_shapes_in_region)
+ (TestPostGISShapestorePoint.test_shape_raw_data)
+ (TestPostGISShapestorePoint.test_shape_points)
+ (TestPostGISShapestorePoint.test_shape_shapeid)
+ (TestPostGISShapestorePoint.test_all_shapes)
+ (TestPostGISTable.test_simple_query)
+ (TestPostGISTable.test_simple_query)
+ (TestPostGISTable.test_simple_query)
+ (TestPostGISTable.test_read_value)
+ (TestPostGISTable.test_read_row_as_dict): Adapt to the new
+ shapeids in the landmarks table
+
+ * test/test_memory_table.py
+ (TestMemoryTable.test_read_row_as_dict_row_count_mode)
+ (TestMemoryTable.test_read_value_row_count_mode)
+ (TestMemoryTable.test_row_id_to_ordinal)
+ (TestMemoryTable.test_row_oridnal_to_id): New test for the new
+ table methods and the new arguments
+
+ * test/test_dbf_table.py
+ (TestDBFTable.test_read_row_as_dict_row_count_mode)
+ (TestDBFTable.test_read_value_row_count_mode)
+ (TestDBFTable.test_row_id_to_ordinal)
+ (TestDBFTable.test_row_oridnal_to_id): New test for the new table
+ methods and the new arguments
+
+2003-08-26 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (PostGISShapeStore.BoundingBox): Use a
+ more postgis specific but much faster method to get the bounding
+ box
+
+2003-08-26 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (PostGISTable.Title)
+ (PostGISShapeStore.AllShapes): Add these missing methods.
+ (PostGISShapeStore.ShapesInRegion): No need to raise
+ StopIteration. We can simply return
+
+ * test/test_postgis_db.py (TestPostGISTable.test_title)
+ (TestPostGISShapestorePoint.test_all_shapes): New tests for the
+ new methods
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (shapetype_map): Add MUTLIPOLYGON.
+
+ * test/test_postgis_db.py (PolygonTests): New class containing
+ those tests from TestPostGISShapestorePolygon that can also be
+ used to test MUTLIPOLYGON tables
+ (TestPostGISShapestorePolygon): Most tests are now in PolygonTests
+ so derive from that
+ (TestPostGISShapestoreMultiPolygon): New class with tests for
+ MUTLIPOLYGON tables
+
+ * test/postgissupport.py (PostGISDatabase.initdb): Allow the
+ tables argument to have tuples with three items to override the
+ WKT type used.
+ (PostgreSQLServer.get_default_static_data_db): Use the above to
+ create a polygon table with MUTLIPOLYGONs
+ (point_to_wkt, coords_to_point, polygon_to_wkt, coords_to_polygon)
+ (arc_to_wkt, coords_to_multilinestring): Rename from *_to_wkt to
+ coords_to*
+ (coords_to_multipolygon): New. Convert to MUTLIPOLYGON
+ (wkt_converter): New. Map WKT types to converters
+ (upload_shapefile): New parameter force_wkt_type to use a
+ different WKT type than the default
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py
+ (ThubanApplication.run_db_param_dialog): New. Suitable as a
+ db_connection_callback. Main difference is that the dialog run
+ from this method doesn't have a parent so it can be used even when
+ there is no main window
+ (ThubanApplication.OpenSession): Use self.run_db_param_dialog if
+ no db_connection_callback was given. This way the dialog pops up
+ even when the .thuban file was given as a command line parameter.
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.OnLeftUp): Release the the mouse
+ before calling MouseLeftUp. MouseLeftUp may pop up modal dialogs
+ which leads to an effectively frozen X session because the user
+ can only interact with the dialog but the mouse is still grabbed
+ by the canvas.
+ Also, call the tool's Hide method before MouseLeftUp because
+ MouseLeftUp may change the tool's coordinates.
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.OpenSession): Catch
+ LoadCancelled exceptions and handle them by returning immediately.
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ GUI part of loading sessions with postgis connections which may
+ require user interaction to get passwords or updated parameters
+
+ * Thuban/UI/dbdialog.py (DBDialog): Reimplement to make it look a
+ bit nucer and be more generic.
+ (DBFrame.OnAdd): Adapt to new DBDialog interface
+
+ * Thuban/UI/application.py (ThubanApplication.OpenSession): New
+ optional parameter db_connection_callback which is passed to
+ load_session.
+
+ * Thuban/UI/mainwindow.py (MainWindow.run_db_param_dialog): New.
+ Suitable as a db_connection_callback
+ (MainWindow.OpenSession): Use self.run_db_param_dialog as the
+ db_connection_callback of the application's OpenSession method
+
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ Basic loading of sessions containing postgis connections:
+
+ * Thuban/Model/load.py (LoadError): Add doc-string
+ (LoadCancelled): New exception class to indicate a cancelled load
+ (SessionLoader.__init__): Add the db_connection_callback parameter
+ which will be used by the loader to get updated parameters and a
+ password for a database connection
+ (SessionLoader.__init__): Add the new XML elements to the
+ dispatchers dictionary
+ (SessionLoader.check_attrs): Two new conversions, ascii to convert
+ to a byte-string object and idref as a generic id reference
+ (SessionLoader.start_dbconnection)
+ (SessionLoader.start_dbshapesource): New. Handlers for the new XML
+ elements
+ (load_session): Add the db_connection_callback to pass through the
+ SessionLoader
+
+ * test/test_load.py (TestPostGISLayer, TestPostGISLayerPassword):
+ New classes to test loading of sessions with postgis database
+ connections.
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (__ThubanVersion__): Remove this and
+ replace it and the comment with __BuildDate__ by the Source: and
+ Id: cvs keywords as used in the other files.
+
+2003-08-25 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.check_attrs): Raise a
+ LoadError when a required attribute is missing. The code used to
+ be commented out for some reason, but probably should have been
+ active.
+
+ * test/test_load.py (TestLoadError.test): Test the message in the
+ LoadError too to make sure it really is about the missing
+ attribute
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_save.py (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table): Add XML validation tests.
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ Implement saving a session with a postgis connection
+
+ * Resources/XML/thuban-0.9.dtd (dbconnection, dbshapesource) New
+ elements for database connections and shapestores using db
+ connections
+ (session): Add the dbconnections to the content model
+
+ * Thuban/Model/save.py (SessionSaver.write_db_connections): New.
+ Write the db connections
+ (SessionSaver.write_session): Call write_db_connections to write
+ the connection before the data sources
+ (SessionSaver.write_data_containers): Handle postgis shapestores
+
+ * test/test_save.py (SaveSessionTest.thubanids)
+ (SaveSessionTest.thubanidrefs): Update for new DTD
+ (SaveSessionTest.test_save_postgis): New. Test saving a session
+ with postgis connections
+
+ * Thuban/Model/postgisdb.py (PostGISTable.DBConnection)
+ (PostGISTable.TableName): New accessor methods for the connection
+ and table name
+
+ * test/test_postgis_db.py (TestPostGISTable.test_dbconn)
+ (TestPostGISTable.test_dbname): New methods to test the new
+ PostGISConnection methods
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/postgisdb.py (ConnectionError): New exception class
+ for exceptions occurring when establishing a Database connection
+ (PostGISConnection.connect): Catch psycopg.OperationalError during
+ connects and raise ConnectionError.
+
+ * test/test_postgis_db.py (TestPostgisDBExceptions): New class for
+ tests for database exceptions
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ Prepare the test suite for tests with required authentication
+
+ * test/postgissupport.py (PostgreSQLServer.__init__): Add instance
+ variables with two predefined users/passwords, one for the admin
+ and one for a non-privileged user.
+ (PostgreSQLServer.createdb): Pass the admin name to initdb and add
+ the non-privileged user to the database and set the admin password
+ (PostgreSQLServer.wait_for_postmaster): Use the admin user name.
+ Better error reporting
+ (PostgreSQLServer.connection_params)
+ (PostgreSQLServer.connection_string): New methods to return
+ information about how to connect to the server
+ (PostgreSQLServer.execute_sql): New. Convenience method to execute
+ SQL statements
+ (PostgreSQLServer.require_authentication): Toggle whether the
+ server requires authentication
+ (PostgreSQLServer.create_user, PostgreSQLServer.alter_user): New.
+ Add or alter users
+ (PostGISDatabase.initdb): Pass the admin name one the
+ subprocesses' command lines. Grant select rights on
+ geometry_columns to everybody.
+ (upload_shapefile): Use the admin name and password when
+ connecting. Grant select rights on the new table to everybody.
+
+ * test/test_viewport.py (TestViewportWithPostGIS.setUp): Use the
+ server's new methods to get the connection parameters.
+
+ * test/test_postgis_session.py (TestSessionWithPostGIS.setUp)
+ (TestSessionWithPostGIS.test_remove_dbconn_exception): Use the
+ server's new methods to get the connection parameters.
+
+ * test/test_postgis_db.py
+ (TestPostGISConnection.test_gis_tables_empty)
+ (TestPostGISConnection.test_gis_tables_non_empty)
+ (PostGISStaticTests.setUp): Use the server's new methods to get
+ the connection parameters.
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Add the psycopg version.
+
+ * Thuban/version.py: Add psycopg version
+
+ * Thuban/Model/postgisdb.py (psycopg_version): New. Return the
+ version of the psycopg module
+
+2003-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/dbdialog.py (DBPwdDlg): Removed because it's not used.
+ (DBFrame.OnEdit): Removed because it's not used and wouldn't work
+ at the moment. The functionality should probably be implemented
+ some time, though.
+ (DBFrame.OnRemove): Display a message if the connection can't be
+ removed because it's still in use.
+
+2003-08-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): split up the huge about
+ text into elements/lists for easier translation. This fixes bug
+ https://intevation.de/rt/webrt?serial_num=2058
+ Also, made some forgotten string available for the i18n.
+
+2003-08-21 Bernhard Herzog <bh at intevation.de>
+
+ Make postgis support really optional including insensitive menu
+ items.
+
+ * Thuban/Model/postgisdb.py (has_postgis_support): New. Return
+ whether the postgis is supported.
+
+ * Thuban/UI/dbdialog.py: Put the psycopg import into try..except
+ to make postgis support optional
+
+ * Thuban/UI/mainwindow.py (_has_postgis_support): New. Context
+ version of Thuban.Model.postgisdb.has_postgis_support
+ (database_management command): Make it only sensitive if postgis
+ is supported.
+
+2003-08-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added CVS revision for rev-history.
+ (section Adding and Removing Layers): Added text and described
+ multi-selection.
+ (chapter Extensions): New.
+
+2003-08-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddLayer): Changed dialog
+ settings to allow multiple files to load into the map.
+ Also reduced selection to *.shp as a default.
+
+2003-08-20 Bernhard Herzog <bh at intevation.de>
+
+ Add dialogs and commands to open database connections and add
+ database layers.
+
+ * Thuban/UI/mainwindow.py (MainWindow.DatabaseManagement): New
+ method to open the database connection management dialog
+ (MainWindow.AddDBLayer): New method to add a layer from a database
+ (_has_dbconnections): New helper function to use for sensitivity
+ (database_management command, layer_add_db command): New commands
+ that call the above new methods.
+ (main_menu): Add the new commands to the menu.
+
+ * Thuban/Model/postgisdb.py (PostGISConnection.__init__)
+ (PostGISConnection.connect): Establish the actual connection in a
+ separate method and call it in __init__. This makes it easier to
+ override the behavior in test cases
+ (PostGISConnection.BriefDescription): New method to return a brief
+ description for use in dialogs.
+
+ * test/test_postgis_db.py (NonConnection): DB connection that
+ doesn't actually connect
+ (TestBriefDescription): New class with tests for the new
+ BriefDescription method
+
+2003-08-19 Jan-Oliver Wagner <jan at intevation.de>
+
+ Moved anything from extensions to libraries.
+
+ * libraries: New.
+
+ * libraries/ pyprojection, pyshapelib, shapelib, thuban: New.
+
+ * libraries/pyprojection/ LICENSE, MANIFEST.in, Projection.i,
+ Projection.py, Projection_wrap.c, setup.py, swighelp.txt: These files have
+ been moved here from thuban/extensions/pyprojection/
+ See there in the Attic for the older history.
+
+ * libraries/pyshapelib/ COPYING, ChangeLog, NEWS, README, dbflib.i,
+ dbflib.py, dbflib_wrap.c, pyshapelib_api.h, pytest.py, setup.py,
+ shapelib.i, shapelib.py, shapelib_wrap.c, shptreemodule.c: These files
+ have been moved here from thuban/extensions/pyshapelib/
+ See there in the Attic for the older history.
+
+ * libraries/shapelib/ dbfopen.c, shapefil.h, shpopen.c, shptree.c: These
+ files have been moved here from thuban/extensions/shapelib/
+ See there in the Attic for the older history.
+
+ * libraries/thuban/ bmpdataset.cpp, cpl_mfile.cpp, cpl_mfile.h,
+ gdalwarp.cpp, wxproj.cpp: These files have been moved here from
+ thuban/extensions/thuban/
+ See there in the Attic for the older history.
+
+ * MANIFEST.in, setup.cfg, setup.py: renamed extensions to libraries.
+
+ * extensions/thuban/ bmpdataset.cpp, cpl_mfile.cpp, cpl_mfile.h,
+ gdalwarp.cpp, wxproj.cpp: Moved to libraries/thuban.
+
+ * extensions/shapelib/ dbfopen.c, shapefil.h, shpopen.c, shptree.c:
+ Moved to libraries/shapelib.
+
+ * extensions/pyshapelib/ COPYING, NEWS, dbflib.py, pytest.py,
+ shapelib.py, README, dbflib_wrap.c, setup.py, shapelib_wrap.c,
+ ChangeLog, dbflib.i, pyshapelib_api.h, shapelib.i, shptreemodule.c:
+ Moved to libraries/pyshapelib.
+
+ * extensions/pyprojection/ MANIFEST.in, Projection.py, setup.py,
+ LICENSE, Projection.i, Projection_wrap.c, swighelp.txt:
+ Moved to libraries/pyprojection.
+
+ * extensions/ pyprojection, pyshapelib, shapelib, thuban: Removed.
+
+ * extensions: Removed.
+
+2003-08-19 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py (ViewPortTest): We don't use the
+ facilities of FileTestMixin so don't derive from it.
+ (TestViewportWithPostGIS): New class with tests for using a
+ viewport on a map with postgis layers.
+
+2003-08-19 Bernhard Herzog <bh at intevation.de>
+
+ Add the db connection management to the session.
+
+ * Thuban/Model/session.py (Session.__init__): New instance
+ variable db_connections
+ (Session.AddDBConnection, Session.DBConnections)
+ (Session.HasDBConnections, Session.CanRemoveDBConnection)
+ (Session.RemoveDBConnection): New methods to manage and query the
+ db connections managed by the session
+ (Session.OpenDBShapeStore): New method to open a shapestore from a
+ db connection
+
+ * Thuban/Model/messages.py (DBCONN_REMOVED, DBCONN_ADDED): New
+ messages for the db connection handling in the session
+
+ * test/test_postgis_session.py: New. test cases for the session's
+ db connection handling with postgis connections
+
+2003-08-19 Bernhard Herzog <bh at intevation.de>
+
+ Add very basic postgis database support and the corresponding test
+ cases. The test cases require a PostgreSQL + postgis installation
+ but no existing database. The database will be created
+ automatically by the test cases
+
+ * test/README: Add note about skipped tests and the requirements
+ of the postgis tests.
+
+ * Thuban/Model/postgisdb.py: New. Basic postgis database support.
+
+ * test/test_postgis_db.py: New. Test cases for the postgis
+ support.
+
+ * Thuban/Model/wellknowntext.py: New. Parser for well-known-text
+ format
+
+ * test/test_wellknowntext.py: New. Test cases for the
+ wellknowntext parser
+
+ * test/postgissupport.py: New. Support module for tests involving
+ a postgis database.
+
+ * test/support.py (execute_as_testsuite): Shut down the postmaster
+ if it's still running after the tests
+
+ * Thuban/Model/data.py (RAW_WKT): New constant for raw data in
+ well known text format
+
+2003-08-19 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Examples/simple_extensions/hello_world.py: New. Raises a Hello World
+ message dialog.
+
+2003-08-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (ThubanTestResult.printErrors): Indent the
+ reason for the skips in the output to make it a bit more readable.
+ (execute_as_testsuite): New helper function to run a test suite
+ and print some more information.
+ (run_tests): Use execute_as_testsuite to run the tests
+
+ * test/runtests.py (main): Use execute_as_testsuite to run the
+ tests
+
+2003-08-18 Bernhard Herzog <bh at intevation.de>
+
+ Fix some bugs in Thuban and the test suite that were uncovered by
+ changes introduced in Python 2.3:
+
+ * Thuban/Model/table.py (DBFTable.__init__): Make sure the
+ filename is an absolute name
+
+ * Thuban/Model/layer.py (RasterLayer.__init__): Make sure the
+ filename is an absolute name
+
+ * test/test_save.py (SaveSessionTest.testRasterLayer): Use a
+ unique filename to save to and use the correct relative filename
+ in the expected output.
+ (SaveSessionTest.test_dbf_table): Use the correct relative
+ filename in the expected output.
+
+ * test/test_layer.py (TestLayer.test_raster_layer): Update the
+ test to check whether the filename is absolute.
+
+2003-08-18 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Added Silke Reimer.
+
+2003-08-15 Bernhard Herzog <bh at intevation.de>
+
+ Change the way shapes are returned by a shape store. The
+ ShapesInRegion method returns an iterator over actual shape
+ objects instead of a list of shape ids.
+
+ * Thuban/Model/data.py (ShapefileShape.ShapeID): New. Return shape
+ id.
+ (ShapefileStore.ShapesInRegion): Return an iterator over the
+ shapes which yields shape objects instead of returning a list of
+ shape ids
+ (ShapefileStore.AllShapes): New. Return an iterator over all
+ shapes in the shape store
+ (DerivedShapeStore.AllShapes): New. Like in ShapefileStore
+
+ * Thuban/Model/layer.py (Layer.ShapesInRegion): Update
+ doc-string.
+
+ * Thuban/UI/baserenderer.py
+ (BaseRenderer.layer_ids, BaseRenderer.layer_shapes): Rename to
+ layer_shapes and make it return an iterator containg shapes
+ instead of a list of ids.
+ (BaseRenderer.draw_shape_layer): Update doc-string; Adapt to
+ layer_shapes() change
+
+ * Thuban/UI/renderer.py (ScreenRenderer.layer_ids)
+ (ScreenRenderer.layer_shapes): Rename as in BaseRenderer
+
+ * Thuban/UI/viewport.py (ViewPort._find_shape_in_layer): Adapt to
+ changes in the ShapesInRegion return value.
+ (ViewPort._get_hit_tester): Remove commented out code
+
+ * test/mockgeo.py (SimpleShapeStore.ShapesInRegion): Adapt to the
+ new return value.
+ (SimpleShapeStore.AllShapes): New. Implement this method too.
+
+ * test/test_layer.py (TestLayer.test_arc_layer)
+ (TestLayer.test_polygon_layer, TestLayer.test_point_layer)
+ (TestLayer.test_point_layer_with_projection)
+ (TestLayer.test_derived_store): Adapt to changes in the
+ ShapesInRegion return value.
+
+ * test/test_shapefilestore.py
+ (TestShapefileStoreArc.test_shapes_in_region)
+ (TestShapefileStorePolygon.test_shapes_in_region)
+ (TestShapefileStorePoint.test_shapes_in_region): Adapt to changes
+ in the ShapesInRegion return value.
+ (TestShapefileStorePoint.test_all_shapes)
+ (TestShapefileStoreArc.test_shape_shapeid): New tests for the new
+ methods
+
+ * test/test_derivedshapestore.py
+ (TestDerivedShapeStore.test_shapes_in_region): Adapt to changes in
+ the ShapesInRegion return value.
+ (TestDerivedShapeStore.test_all_shapes)
+ (TestDerivedShapeStore.test_shape_shapeid): New tests for the new
+ methods
+
+2003-08-15 Bernhard Herzog <bh at intevation.de>
+
+ Make the renderers deal correctly with raw vs. python level
+ representation of shape geometries
+
+ * Thuban/UI/baserenderer.py (BaseRenderer.low_level_renderer):
+ Return a flag useraw in addition to the callable and the parameter
+ to indicate whether the callable can deal with the raw shape data
+ or uses the higher level python lists of coordinates. The callable
+ now should accept either the raw data or the return value of the
+ shape's Points() method.
+ (BaseRenderer.draw_shape_layer): Adapt to the low_level_renderer
+ change
+ (BaseRenderer.projected_points): Instead of the shape id use the
+ points list as parameter.
+ (BaseRenderer.draw_polygon_shape, BaseRenderer.draw_arc_shape)
+ (BaseRenderer.draw_point_shape): Adapt to projected_points()
+ change and accept the points list as parameter instead of the
+ shape id.
+
+ * Thuban/UI/renderer.py (MapRenderer.low_level_renderer): Return
+ the useraw flag as required by the BaseRenderer
+ (ScreenRenderer.draw_shape_layer): Adapt to low-level renderer
+ changes.
+
+ * test/test_baserenderer.py
+ (TestBaseRenderer.test_point_with_classification): New test for
+ rendering a map with classifications.
+
+2003-08-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/viewport.py (ViewPort.find_shape_at)
+ (ViewPort._find_shape_in_layer, ViewPort._find_shape_in_layer)
+ (ViewPort._get_hit_tester, ViewPort.projected_points)
+ (ViewPort._hit_point, ViewPort._hit_arc, ViewPort._hit_polygon)
+ (ViewPort._find_label_at): Split the find_shape_at method into
+ several new methods and use the functions in the hit-test module.
+
+ * Thuban/UI/hittest.py: New module with Python-level hit-testing
+ functions
+
+ * test/test_hittest.py: New. Test for the new hittest module
+
+2003-08-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.ShapesInRegion): Apply the layer
+ projection to all corners of the bounding box to get a better
+ approximation of the projected bounding box
+
+ * test/test_layer.py (TestLayer.test_point_layer_with_projection):
+ New. Test coordinate handling of a layer with a projection.
+ Catches the bug fixed in Layer.ShapesInRegion
+
+2003-08-15 Bernhard Herzog <bh at intevation.de>
+
+ Move some of the mock objects in test_baserenderer into their own
+ module so they can easily be used from other tests
+
+ * test/mockgeo.py: New test helper module with some mock objects
+ for geometry related things like shapes, shapestores and
+ projections.
+
+ * test/test_mockgeo.py: New. Tests for the new helper module
+
+ * test/test_baserenderer.py: Some of the mock-objects are in
+ mockgeo now.
+
+2003-08-12 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Added Björn Broscheit.
+
+2003-08-12 Bernhard Herzog <bh at intevation.de>
+
+ * po/de.po: New. German translations by Bjoern Broscheit
+
+2003-08-12 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (UnknownProjPanel._DoLayout): Translated
+ strings have to be one string literal.
+
+2003-08-11 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (FloatComparisonMixin.assertPointListEquals):
+ New. This method was used in various derived classes, but it's
+ better to have it here.
+
+ * test/test_shapefilestore.py
+ (ShapefileStoreTests.assertPointListEquals): Removed. It's now in
+ FloatComparisonMixin
+
+ * test/test_layer.py (TestLayer.assertPointListEquals): Removed.
+ It's now in FloatComparisonMixin
+
+ * test/test_derivedshapestore.py
+ (TestDerivedShapeStore.assertPointListEquals): Removed. It's now
+ in FloatComparisonMixin
+
+2003-08-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.OnJoin): Add missing space to
+ error message
+
+2003-08-08 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Now use authorgroup. Added revhistory
+ with version number.
+ Changed title to reflect version number of Thuban.
+
+2003-08-08 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/about.py (About.__init__): Reworked the hall of fame. Now
+ the list corresponds to the "About" web page.
+
+2003-08-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/projdialog.py (UTMProposeZoneDialog.dialogLayout):
+ Make sure translated strings are recognized as one string literal.
+
+ * Thuban/UI/proj4dialog.py (UTMProposeZoneDialog.dialogLayout):
+ Make sure translated strings are recognized as one string literal.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.OnOK): Make sure
+ translated strings are recognized as one string literal.
+
+ * Thuban/UI/application.py (ThubanApplication.OpenSession): Make
+ sure translated strings are recognized as one string literal.
+
+2003-08-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/data.py (DerivedShapeStore.RawShapeFormat): New.
+ Simply delegates to the original shapestore.
+
+ * test/test_derivedshapestore.py
+ (TestDerivedShapeStore.test_raw_format): New. Test case for
+ DerivedShapeStore.RawShapeFormat
+
+2003-08-07 Bernhard Herzog <bh at intevation.de>
+
+ Add raw data interface to shape objects.
+
+ * Thuban/Model/data.py (ShapefileShape, Shape): Rname the shape
+ class to ShapefileShape which now holds shapefile specific
+ information.
+ (ShapefileShape.compute_bbox): Simplified to not cache any
+ information. The way this method is used that shouldn't matter
+ performance wise.
+ (ShapefileShape.RawData): New. Return the shapeid which is the raw
+ data format for shapes from shapefiles.
+ (ShapefileStore.RawShapeFormat): New. Return the raw datatype used
+ in the shape objects returned by a shapestore. For a
+ ShapefileStore this is always RAW_SHAPEFILE.
+ (RAW_PYTHON, RAW_SHAPEFILE): Constants for the RawShapeFormat
+ method.
+
+ * test/test_shapefilestore.py
+ (TestShapefileStore.test_raw_format): New test to test the raw
+ format feature of shapes.
+
+ * Thuban/Model/layer.py: Remove the unused import of Shape from
+ data. It was only there for interface compatibility but it's not
+ used inside of Thuban and the generic Shape class has gone away.
+
+ * Thuban/UI/renderer.py (MapRenderer.low_level_renderer): Check
+ the raw data format and only use an optimized version of its a
+ shapefile.
+
+2003-08-07 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_baserenderer.py (SimpleShape): Shape class for the
+ tests.
+ (SimpleShapeStore.Shape): Use SimpleShape instead of
+ Thuban.Model.data.Shape to make the tests independed of the coming
+ changes.
+
+2003-08-07 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (SkipTest, ThubanTestResult, ThubanTestRunner)
+ (ThubanTestProgram): New classes that extend the respective
+ classes from unittest. These new version support skipping tests
+ under certain expected conditions. In the Thuban test suite we
+ uses this for tests that require the optional gdal support.
+ (run_tests): Use ThubanTestProgram instead of the unittest.main()
+
+ * test/runtests.py (main): Use the new ThubanTestRunner instead of
+ the normal one from unittest
+
+ * test/test_layer.py (TestLayer.test_raster_layer): If this test
+ is not run because gdal support isn't available report this to the
+ runner.
+
+ * test/test_baserenderer.py
+ (TestBaseRenderer.test_raster_no_projection): Do not run this test
+ if gdal support isn't available and report this to the runner.
+
+2003-08-06 Bernhard Herzog <bh at intevation.de>
+
+ Rearrange the renderers a bit, partly in preparation for changes
+ required for the postgis merge, partly to make it more testable.
+ Also make the representation of coordinates in Shapes more
+ consistent.
+
+ * Thuban/UI/renderer.py (MapRenderer): Most of the code/methods in
+ this class is now in BaseRenderer. This class is now practically
+ only a specialization of BaseRenderer for rendering to an actual
+ wx DC.
+ (ScreenRenderer.draw_shape_layer): Use self.low_level_renderer()
+ to get the shapetype specific rendering functions.
+
+ * Thuban/UI/baserenderer.py: New file with the basic rendering
+ logic. The code in this file is completely independend of wx.
+ (BaseRenderer): Class with the basic rendering logic
+
+ * test/test_baserenderer.py: New. Test cases for BaseRenderer
+
+ * Thuban/UI/view.py (MapCanvas.__init__): New instance variable
+ error_on_redraw to guard agains endless loops and stack overflows
+ when there's a bug in the rendering code that raises exceptions.
+ (MapCanvas.OnIdle, MapCanvas._do_redraw): Split the actual
+ rendering into a separate method _do_redraw so that error handling
+ is a bit easier. When an exception occurs, set error_on_redraw to
+ true. When it's true on entry to OnIdle do nothing and return
+ immediately.
+
+ * Thuban/Model/data.py (ShapefileStore.Shape): For consistency, a
+ Shape object will always have the coordinates as a list of list of
+ coordinate pairs (tuples).
+ (Shape.compute_bbox): Adapt to new representation.
+
+ * Thuban/UI/viewport.py (ViewPort.find_shape_at)
+ (ViewPort.LabelShapeAt): Adapt to new coordinate representation in
+ Shape objects.
+
+ * test/test_shapefilestore.py
+ (ShapefileStoreTests.assertFloatTuplesEqual)
+ (ShapefileStoreTests.assertPointListEquals): Rename to
+ assertPointListEquals and change purpose to checking equality of
+ the lists returned by Shape.Points().
+ (TestShapefileStoreArc.test_shape)
+ (TestShapefileStorePolygon.test_shape)
+ (TestShapefileStorePoint.test_shape): Use the new
+ assertPointListEquals instead of assertFloatTuplesEqual
+
+ * test/test_layer.py (TestLayer.assertFloatTuplesEqual)
+ (TestLayer.assertPointListEquals): Rename to assertPointListEquals
+ and change purpose to checking equality of the lists returned by
+ Shape.Points().
+ (TestLayer.test_arc_layer, TestLayer.test_arc_layer)
+ (TestLayer.test_polygon_layer, TestLayer.test_point_layer)
+ (TestLayer.test_derived_store): Use the new assertPointListEquals
+ instead of assertFloatTuplesEqual
+
+ * test/test_derivedshapestore.py
+ (TestDerivedShapeStore.assertFloatTuplesEqual)
+ (TestDerivedShapeStore.assertPointListEquals): Rename to
+ assertPointListEquals and change purpose to checking equality of
+ the lists returned by Shape.Points().
+ (TestDerivedShapeStore.test_shape): Use the new
+ assertPointListEquals instead of assertFloatTuplesEqual
+
+2003-08-06 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/projdialog.py (UTMPanel._OnPropose): Added test for
+ a bounding box. A dialog is raised in case, no bounding box
+ is found. This fixes bug #2043:
+ https://intevation.de/rt/webrt?serial_num=2043
+
+2003-08-05 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/color.py (Color.__repr__): Make the repr of a color
+ object look like a Color instantiation. Formerly it looked like a
+ tuple.
+
+ * test/test_color.py (TestColor.test_repr)
+ (TestColor.test_equality, TestColor.test_inequality): New. test
+ some more apects of the Color class
+ (TestTransparent.test_repr, TestTransparent.test_hex)
+ (TestTransparent.test_equality): New. Test cases for the
+ Transparent object.
+
+2003-08-04 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: a number of small improvements.
+ The resulting file is the version submitted for GREAT-ER II.
+
+2003-08-01 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/resource.py, Thuban/UI/projdialog.py,
+ Thuban/UI/join.py, Thuban/UI/classgen.py, Thuban/UI/about.py,
+ Thuban/Model/resource.py: Insert cvs keywords and doc-strings.
+
+ * Thuban/UI/common.py: Insert cvs keywords and doc-strings.
+ (Color2wxColour, wxColour2Color, ThubanBeginBusyCursor)
+ (ThubanEndBusyCursor): Add doc-strings
+
+2003-08-01 Bernhard Herzog <bh at intevation.de>
+
+ First step towards PostGIS integration. More abstraction by movin
+ more code from the layer to the shapestore. More methods of the
+ layer are now simply delegated to the equivalent method of the
+ shapestore. The SHAPETYPE_* constants are now in data not in
+ layer.
+
+ * Thuban/Model/data.py (SHAPETYPE_POLYGON, SHAPETYPE_ARC)
+ (SHAPETYPE_POINT, Shape): Move these constants and classes from
+ layer.py to data.py
+ (ShapefileStore.__init__): More Initialization for the new methods
+ and functionality.
+ (ShapefileStore.ShapeType, ShapefileStore.NumShapes)
+ (ShapefileStore.BoundingBox, ShapefileStore.ShapesInRegion)
+ (ShapefileStore.Shape): New methods that were formerly implemented
+ in the layer.
+ (DerivedShapeStore.Shape, DerivedShapeStore.ShapesInRegion)
+ (DerivedShapeStore.ShapeType, DerivedShapeStore.NumShapes)
+ (DerivedShapeStore.BoundingBox): New. DerivedShapeStore
+ equivalents of the new shape methods. These versions are simply
+ delegated to the original shapstore.
+
+ * Thuban/Model/layer.py (SHAPETYPE_POLYGON, SHAPETYPE_ARC)
+ (SHAPETYPE_POINT, Shape): Removed. They're now in data.py
+ (Layer.SetShapeStore): Removed the initializatin of instance
+ variables that were needed for the stuff that's now in
+ ShapefileStore
+ (Layer.BoundingBox, Layer.NumShapes, Layer.ShapeType)
+ (Layer.Shape, Layer.ShapesInRegion): Simply delegate to the
+ shapestore.
+
+ * Thuban/UI/classifier.py, Thuban/UI/renderer.py,
+ Thuban/UI/viewport.py: Import the SHAPETYPE_* constants from data
+ instead of layer.
+
+ * test/test_shapefilestore.py: New. Tests for ShapefileStore.
+
+ * test/test_derivedshapestore.py: New. Tests for DerivedShapeStore.
+
+ * test/test_layer.py: Import the SHAPETYPE_* constants from data
+ instead of layer.
+ (TestLayer.test_derived_store): Remove the test for the exception
+ when instantiating the DerivedShapeStore with an incompatible
+ table which is now in test_derivedshapestore.py. Add some more
+ tests of the layer methods to determine whether they work for a
+ DerivedShapeStore as well.
+
+2003-07-31 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Fix the list of required packages
+ by just listing the name and where they can be found.
+
+2003-07-31 Frank Koormann <frank.koormann at intevation.de>
+
+ * Doc/manual/thuban-manual.xml:
+ Changed the screenshot elements to figure.
+ Changed some variablelist elements to itemizedlist.
+ Added section on GDAL formats.
+
+2003-07-31 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added a few sentences about
+ the Fix Border Color option when generating classes.
+
+2003-07-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py: Add docstrings. Rename specific
+ Ramp instances to use lower_case_style.
+
+ * Thuban/UI/classgen.py: Use renamed Ramp instances.
+
+ * Thuban/UI/classifier.py: Add docstrings.
+
+ * Thuban/UI/dock.py: Add docstrings.
+
+ * test/test_classgen.py: Use renamed Ramp instances.
+
+2003-07-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Lib/connector.py (QueueingPublisher): Removed. This class
+ was never used in Thuban.
+
+2003-07-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.__init__): Use the table's Title()
+ method directly instead of going through the transient_table
+ method. This faster because transient_table may force the copy of
+ a DBF file into the transient database and setting a table's title
+ doesnm't affect the title of the associated transient table, so
+ this fixes RT #2042
+
+ * Thuban/UI/main.py (__version__): Don't import the already
+ removed show_exception_dialog.
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.ShowExceptionDialog):
+ Put back this method and remove the equivalent function since we
+ are setting the exception hook from within this class (OnInit).
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/images/5_2_custom_ramp.png,
+ Doc/manual/images/5_2_quantiles.png,
+ Doc/manual/images/5_2_uniform_dist.png,
+ Doc/manual/images/5_2_unique_values.png,
+ Doc/manual/images/8_int_error.png: New screen shots.
+
+ * Doc/manual/thuban-manual.xml: Fixed typos and wording, clarified
+ some points, and added more screen shots.
+
+2003-07-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/data.py: Remove the now unused import of warnings
+
+2003-07-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/data.py (SimpleStore): Removed. This class has been
+ deprecated since before the 0.8 release and isn't used in Thuban
+ itself anymore.
+
+ * Thuban/Model/transientdb.py: Remove some unnecessary imports
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): set the
+ python exception hook here so that we are sure to catch any
+ Thuban exception that happen during initialization.
+
+ * Thuban/UI/main.py (main): Don't set the exception hook here,
+ it will get set in ThubanApplication.OnInit.
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.ShowExceptionDialog):
+ Removed and called it show_exception_dialog() so that the exception
+ handler can be set before the class is created.
+
+ * Thuban/UI/main.py (main): Install the exception handler before
+ a ThubanApplication is created.
+
+2003-07-29 Bernhard Herzog <bh at intevation.de>
+
+ * po/it.po: New. Italian translation by Maurizio Napolitano
+
+ * po/ru.po: New. Russian translation by Alex Shevlakov
+
+2003-07-29 Frank Koormann <frank.koormann at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Extended section on supported
+ projections.
+
+2003-07-29 Frank Koormann <frank.koormann at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: gaspell-checked.
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/images/3_5_legend.png: Added border to improve look
+ on white background.
+
+2003-07-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Fixed grammar and typos. Added
+ descriptions for the legend toolbar.
+
+ * Doc/manual/images/4_2_raster_layer_properties.png: Removed
+ cursor from dialog box.
+
+2003-07-28 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: More screenshots and more chapters.
+
+ * Doc/manual/images/2_4_session_tree.png,
+ Doc/manual/images/3_5_legend.png, Doc/manual/images/3_rename_map.png,
+ Doc/manual/images/4_2_layer_properties.png,
+ Doc/manual/images/4_2_raster_layer_properties.png,
+ Doc/manual/images/5_3_genclass.png,
+ Doc/manual/images/5_classification.png,
+ Doc/manual/images/6_projection.png,
+ Doc/manual/images/7_1_table_view.png,
+ Doc/manual/images/7_2_5_join.png: New screenshots.
+
+2003-07-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Chapter on Projection Management.
+
+2003-07-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added EPS images and wrote
+ chapter on Layer Management.
+
+ * Doc/manual/Makefile: New. Makefile to generate all formats for the
+ manual and images.
+
+2003-07-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/range.py, Thuban/version.py: Remove the #! line as
+ it annoys lintian which warns about these files not being
+ executable. The #! isn't necessary here since if you absolutely
+ must execute them you can always say "python <filename>".
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_shape_layer): Remove
+ superfluous code to set brush and pen for point shapes
+
+ * Thuban/UI/viewport.py: Remove commented out code that wouldn't
+ belong in viewport anyway
+
+2003-07-24 Frank Koormann <frank.koormann at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added section on table management.
+
+2003-07-24 Bernhard Herzog <bh at intevation.de>
+
+ * test/runtests.py (main): Recognize the long "verbose" option
+ correctly.
+
+2003-07-22 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Continue to write first revision
+ of the manual.
+
+ * Thuban/UI/renderer.py (MapRenderer.render_map): Wrap method
+ with Begin/EndDrawing() calls to ensure we aren't doing to
+ many updates to the dc during rendering.
+ (ScreenRenderer.draw_shape_layer): self.draw_point_shape takes
+ a pen and brush argument so they need to be passed to the function.
+
+ * Thuban/UI/viewport.py (ViewPort.calc_min_max_scales): New.
+ Calculates the minimum and maximum scale values. Factored out
+ of set_view_transform so that it could be used to zoom all the
+ way into a single point.
+ (ViewPort.set_view_transform): Call calc_min_max_scales().
+ (ViewPort.FitSelectedToWindow): Zoom to the maximum scale
+ if only a single point is selected.
+
+ * Doc/manual/images/1_2_legend_close.png,
+ Doc/manual/images/1_2_legend_dock.png,
+ Doc/manual/images/1_2_mainwindow.png,
+ Doc/manual/images/1_2_mainwindow.ps,
+ Doc/manual/images/1_2_mainwindow.sk,
+ Doc/manual/images/3_2_fullextent.png,
+ Doc/manual/images/3_2_fulllayerextent.png,
+ Doc/manual/images/3_2_fullshapeextent.png,
+ Doc/manual/images/3_2_pan.png,
+ Doc/manual/images/3_2_zoomin.png,
+ Doc/manual/images/3_2_zoomout.png,
+ Doc/manual/images/3_3_identify.png,
+ Doc/manual/images/3_3_label.png,
+ Doc/manual/images/3_5_invisible.png,
+ Doc/manual/images/3_5_movedown.png,
+ Doc/manual/images/3_5_moveup.png,
+ Doc/manual/images/3_5_props.png,
+ Doc/manual/images/3_5_tobottom.png,
+ Doc/manual/images/3_5_totop.png,
+ Doc/manual/images/3_5_visible.png: New. Images for the documentation.
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/messages.py (MAP_REPLACED): New message.
+
+ * Thuban/UI/viewport.py (ViewPort.SetMap): Issue MAP_REPLACED
+ after the new map has been assigned
+
+ * Thuban/UI/mainwindow.py (MainWindow.delegated_messages):
+ Delegate MAP_REPLACED to the canvas too
+ (MainWindow.prepare_new_session): Removed. Thanks to the new
+ MAP_REPLACED message it's no longer needed
+ (MainWindow.OpenSession, MainWindow.NewSession):
+ prepare_new_session has been removed.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Subscribe to
+ MAP_REPLACED so that we can close the dialog if a new map is set.
+ (Classifier.unsubscribe_messages): Unsubscribe from MAP_REPLACED
+ (Classifier.map_replaced): Handle MAP_REPLACED by closing the
+ dialog
+
+ * test/test_viewport.py (SimpleViewPortTest)
+ (SimpleViewPortTest.test_default_size): Add doc-strings
+ (ViewPortTest.setUp): Bind map to self.map so we can use it in
+ tests. Subscribe to MAP_REPLACED messages too.
+ (ViewPortTest.tearDown): No need to explicitly unsubscribe
+ (ViewPortTest.test_set_map): New test for the SetMap method.
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_viewport.py (SimpleViewPortTest.test_default_size):
+ Move this test from ViewPortTest.setUp to this new separate test
+ case. setUp is not the place for the actual tests.
+ (ViewPortTest.test_inital_settings, ViewPortTest.setUp): Move some
+ more of the test from setUp to the new test test_inital_settings.
+ (ViewPortTest.test_win_to_proj, ViewPortTest.test_proj_to_win)
+ (ViewPortTest.test_proj_conv): Split test_proj_conv into
+ test_win_to_proj and test_proj_to_win and make the tests easier to
+ understand
+ (ViewPortTest.testFitRectToWindow, ViewPortTest.testZoomFactor)
+ (ViewPortTest.testZoomOutToRect, ViewPortTest.testTranslate)
+ (ViewPortTest.test_unprojected_rect_around_point)
+ (ViewPortTest.test_find_shape_at, ViewPortTest.testTools):
+ Reformat to increase readability.
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.OnLeftDown): Capture the mouse.
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/runtests.py: The test suite can now be run without an X
+ connection. To make sure this remains true, remove the DISPLAY
+ environment variable so that an error occurs if the wxGTK is
+ imported accidentally
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/viewport.py: Remove unused imports
+
+ * Thuban/UI/view.py: Remove unused imports
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_export.py Remove unused imports. The OutputTransform
+ function is now in viewport.py and is called output_transform
+ (TestScalebar.test_output_transform)
+ (TestScalebar.test_OutputTransform): Renamed to
+ test_output_transform and updated to use output_transform instead
+ of OutputTransform
+
+ * Thuban/UI/view.py (OutputTransform): Moved to viewport.py and
+ renamed.
+ (MapCanvas.Export, MapPrintout.draw_on_dc): OutputTransform was
+ renamed to output_transform
+
+ * Thuban/UI/viewport.py (OutputTransform, output_transform):
+ Rename to output_transform
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.__init__): Rename
+ classificationField to classificatin_column and init it here so
+ that it can be used in SetClassificationColumn
+ (Layer.GetClassificationColumn, Layer.GetClassificationField):
+ Rename to GetClassificationColumn.
+ (Layer.SetClassificationColumn, Layer.SetClassificationField):
+ Rename to SetClassificationColumn and issue a LAYER_CHANGED
+ message if the column changes.
+ (Layer._classification_changed, Layer.ClassChanged): Rename to
+ _classification_changed. Update the callers.
+ (Layer.SetShapeStore): Further field->column renames.
+
+ * Thuban/Model/load.py (SessionLoader.start_classification)
+ (SessionLoader.start_clpoint): Updates because of
+ field->column method name changes in the Layer class
+
+ * Thuban/Model/save.py (SessionSaver.write_classification): Updates
+ because of field->column method name changes in the Layer class
+
+ * Thuban/UI/classifier.py (Classifier.__init__)
+ (Classifier._OnTry, Classifier._OnRevert): Updates because of
+ field->column method name changes in the Layer class
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Updates
+ because of field->column method name changes in the Layer class
+
+ * Thuban/UI/viewport.py (ViewPort.find_shape_at): Updates because
+ of field->column method name changes in the Layer class
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.testClassifiedLayer): Update because of
+ field->column method name changes in the Layer class
+
+ * test/test_layer.py (SetShapeStoreTests.setUp)
+ (SetShapeStoreTests.test_sanity): Update because of field->column
+ method name changes in the Layer class
+ (TestLayerModification.setUp): Subscribe to LAYER_CHANGED as well
+ (TestLayerModification.test_sanity)
+ (TestLayerModification.test_initial_settings): remove unsued code
+ and rename to test_sanity.
+ (TestLayerModification.test_set_classification): New test for
+ SetClassification and SetClassificationField.
+
+2003-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_classgen.py (TestFixedRamp.test): Extend test to check
+ the non-fixed values as well. The old test would have accepted a
+ fixed ramp that only returnes the fixed properties
+
+2003-07-17 Jonathan Coles <jonathan at intevation.de>
+
+ * Doc/manual/mainwindow.png, Doc/manual/mainwindow.xcf: Screen
+ shots for the manual. The XCF file is the source image and
+ has additional layers to support changes.
+
+ * Doc/manual/thuban-manual.xml: Wrote an initial Introduction.
+
+ * Thuban/UI/classifier.py (Classifier.__BuildClassification):
+ Return both the new class and the field name.
+
+ * Thuban/UI/mainwindow.py (MainWindow.ToggleLegend): Don't
+ fit the map to the window as this changes any zoom level that
+ the user may have set.
+
+2003-07-16 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py (generate_singletons,
+ generate_uniform_distribution, generate_quantiles): Remove
+ fixes parameter, but maintain the same functionality by having
+ the calling function pass a FixedRamp object for the ramp.
+ (FixedRamp): New. Adapts a ramp to have fixed property values.
+
+ * Thuban/Model/classification.py: Use new CLASS_CHANGED message.
+ (Classification): Inherit from Publisher.
+ (Classification.__init__): Remove the layer parameter.
+ Classifications no longer need to have a parent layer.
+ (Classification.GetField, Classification.GetFieldType,
+ Classification.SetFieldInfo): Removed. The field name is stored
+ in the layer, and the type can be retreived by calling
+ Layer.GetFieldType().
+ (Classification._set_layer, Classification.GetLayer): Removed.
+ Classifications no longer have a parent layer.
+
+ * Thuban/Model/layer.py (Layer.Destroy): Unsubscribe from the
+ classification.
+ (Layer.SetShapeStore): Reset the classification first while
+ we still have the old shape store to work with.
+ (Layer.GetClassificationField, Layer.SetClassificationField):
+ New. Method for getting/setting the field to classify on.
+ (Layer.SetClassification): Simplified now that the layer
+ simply has to hold a reference to the classification and not
+ tell the classification who owns it.
+ Fixes RTbug #2023.
+
+ * Thuban/Model/load.py (SessionLoader.start_classification):
+ Set the field name on the layer, not the classification.
+
+ * Thuban/Model/messages.py: Add CLASS_CHANGED for when a
+ classification is modified.
+
+ * Thuban/Model/save.py (SessionSaver.write_classification):
+ Get the field name and type from the layer.
+
+ * Thuban/Model/table.py (table_to_dbf, table_to_csv): Renamed
+ parameter records to rows and add docstring. Fixes RTbug #1997.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.OnOK): Use a fixed
+ ramp when we need to fix certain values of a ramp rather than
+ using the old fixes parameter. Fixes RTbug #2024.
+
+ * Thuban/UI/classifier.py (ClassGrid.CreateTable): Add fieldType
+ parameter.
+ (ClassTable.Reset): Add fieldType parameter and use it, rather
+ than asking the classification.
+ (Classifier.__init__): Remember the original class's field
+ and ask the layer for the field type, rather than the classification.
+ (Classifier.__SetGridTable): Retrieve the field and field type
+ for the table because they are not in the classification.
+ (Classifier._OnTry, Classifier._OnRevert): Set the classification
+ field on the layer in addition to the classification itself.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Get the
+ classification field from layer.
+
+ * Thuban/UI/viewport.py (ViewPort.find_shape_at): Get the
+ classification field from layer. Split up tests and remove
+ *-imports. Fixes RTbug #1992.
+
+ * test/test_classgen.py (TestFixedRamp): Test for the FixedRamp class.
+
+ * test/test_classification.py
+ (TestClassification.test_classification): Remove tests for methods
+ that no longer exist.
+
+ * test/test_layer.py (SetShapeStoreTests.setUp): Classification
+ __init__ no longer has a field parameter, use SetClassificationField.
+ (SetShapeStoreTests.test_sanity): Use layer object to get class
+ field info.
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer): Use
+ SetClassificationField on layer to set class field info.
+
+ * test/test_viewport.py: Renamed from test/test_view.py.
+
+2003-07-16 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Added authors and an initial
+ coarse structure.
+
+2003-07-15 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (FloatComparisonMixin): This is a mix-in class
+ and therefore should not be derived from any other class.
+
+ * test/test_range.py (RangeTest): FloatComparisonMixin is a
+ mix-in, so derive from TestCase as well.
+
+2003-07-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Rework the
+ draw_func handling a bit to remove one layer of indirection. This
+ makes the renderer about 10% faster in the non-classifying case
+ and the code a bit cleaner
+ (MapRenderer.draw_point_shape): Add the pen and brush parameters
+ and set them in the dc. Now the draw_point_shape method and
+ wxproj's draw_polygon_shape function have basically the same
+ signature so that both can be directly used as draw_func
+
+2003-07-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/save.py (SessionSaver.write_classification): Encode
+ string values (in addition to the labels) as UTF 8
+
+ * Thuban/Model/load.py (SessionLoader.start_clpoint): Decode the
+ values if the field type is string
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer): Test
+ saving a session with non-ascii string classification values.
+
+ * test/test_load.py (TestClassification.file_contents)
+ (TestClassification.test): Check for non-ascii values in string
+ classifications
+
+2003-07-14 Jonathan Coles <jonathan at intevation.de>
+
+ * test/test_view.py: New. Tests for ViewPort.
+
+2003-07-14 Frank Koormann <frank at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.start_map): Encode map
+ title to latin1. Fixes https://intevation.de/rt/webrt?serial_num=2013
+
+ * test/test_load_0_8.py (TestUnicodeStrings): New, test load of
+ unicode strings from session file: session title, map title and
+ projection name.
+
+2003-07-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/viewport.py (Tool.MouseUp): Should have called
+ drag_stop, not drag_move when the mouse is released.
+
+2003-07-10 Jonathan Coles <jonathan at intevation.de>
+
+ The most important part of this is the seperation of view.py into
+ two pieces. viewport.py now has a class called ViewPort which
+ contains all the non-wx parts of view.py and can therefore be
+ tested. view.py contains only the wx-specific parts and is fairly
+ simple.
+
+ * Thuban/UI/view.py: Stripped out all non-wx functionality. Fixes
+ RTTbug #1992.
+ * Thuban/UI/viewport.py: New. Contains non-wx view functionality.
+ RTTbug #1992.
+
+ * Thuban/Model/classgen.py (generate_singletons,
+ generate_uniform_distribution, generate_quantiles):
+ Added 'fixes' parameter so that property attributes can
+ be held constant over the generated classification groups.
+ (CustomRamp.GetProperties): Remove unused variables.
+
+ * Thuban/Model/map.py (Map.SetProjection): Send the old
+ projection as an argument to listeners of the MAP_PROJECTION_CHANGED
+ event.
+
+ * Thuban/Model/table.py (table_to_dbf, table_to_csv): Added 'records'
+ parameter which is a list of records that restricts which
+ records are saved. Fixes RTbug #1997.
+
+ * Thuban/UI/application.py (ThubanApplication.ShowExceptionDialog):
+ Port exception dialog from GREAT-ER. Fixes RTbug #1993.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__): Add controls
+ to allow the user to fix line color/width on generated groups.
+ (ClassGenDialog.OnOK): Use new 'fixes' parameter of the generate_*
+ functions to optionally fix group properties.
+
+ * Thuban/UI/main.py (main): Set exception hook to the
+ ShowExceptionDialog. Fixes RTbug #1993.
+
+ * Thuban/UI/mainwindow.py (MainWindow.ShowTableView): Raise
+ the table window when it is selectd to be shown.
+
+ * Thuban/UI/tableview.py (QueryTableFrame.__init__): Add an
+ Export Selection button and move the export buttons underneath
+ the table.
+ (QueryTableFrame.UpdateStatusText): Added event argument so
+ that it can respond to grid selection events. The status text
+ is now updated even when the table is not associated with a
+ layer as was previously assumed.
+ (QueryTableFrame.OnGridSelectRange, OnGridSelectCell): Removed.
+ UpdateStatusText responds to these events.
+ (QueryTableFrame.OnSaveAs): Renamed to doExport.
+ (QueryTableFrame.doExport): Helper function that saves the
+ entire table, or selected rows, to a file.
+ (QueryTableFrame.OnExport, QueryTableFrame.OnExportSel): New.
+ Respond to export button events and call doExport.
+
+ * extensions/thuban/gdalwarp.cpp (ProjectRasterFile): Make sure
+ the function doesn't return NULL without first setting a Python
+ Error.
+
+ * test/runtests.py (main): Only print "Unknown option" for
+ unsupported options.
+
+ * test/support.py (FloatComparisonMixin.assertFloatEqual): Take
+ optional epsilon argument to specify floating point accuracy.
+ (FloatComparisonMixin.assertFloatSeqEqual): Call assertFloatEqual
+ for each item test.
+
+ * test/test_csv_table.py (TestCSVTable.test_table_to_cvs): Add
+ tests for saving selected records.
+
+ * test/test_dbf_table.py (TestTableToDBF.test_table_to_dbf): Add
+ tests for saving selected records.
+
+ * test/test_map.py (TestMapWithContents.test_set_projection):
+ MAP_PROJECTION_CHANGED events send the old projection.
+
+ * test/test_session.py
+ (TestSessionWithContent.test_forward_map_projection):
+ MAP_PROJECTION_CHANGED events send the old projection.
+
+ * test/test_table.py (TableTest): Update tests to use non-deprecated
+ functions.
+
+2003-07-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientTableBase.Width): The type
+ constants in the column objects are the standard ones defined in
+ the table module.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transienttable_to_dbf): New. Test whether
+ exporting transient tables as DBF works. This should catch the bug
+ just fixed in TransientTableBase.Width.
+
+2003-07-08 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/classgen.py (CustomRamp.GetProperties): Compute the
+ interpolated colors correctly.
+
+ * test/test_classgen.py (TestCustomRamp.test_color_interpolation):
+ New. Test case for the fix in classgen.py
+
+2003-07-08 Bernhard Herzog <bh at intevation.de>
+
+ * test/runtests.py (main): Make the default output less verbose
+ and add a verbosity option (-v) to get the old output
+
+2003-07-08 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/XML/thuban-0.9.dtd: New. This will become the DTD for
+ 0.9.
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.JoinType):
+ New. Return the join type
+
+ * Thuban/Model/save.py (SessionSaver.write_session): Use new 0.9
+ DTD
+ (SessionSaver.write_data_containers): Save the join type for
+ joined tables
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Add the new 0.9
+ namespace
+ (SessionLoader.start_jointable): Handle the jointype attribute
+
+ * test/test_load_0_8.py: New. Effectively a copy of test_load.py
+ as of Thuban 0.8. These are now tests to determine whether Thuban
+ can still read files generated by Thuban 0.8
+
+ * test/test_load.py (LoadSessionTest.dtd)
+ (TestSingleLayer.file_contents)
+ (TestLayerVisibility.file_contents, TestLabels.file_contents)
+ (TestLayerProjection.file_contents)
+ (TestRasterLayer.file_contents, TestJoinedTable.file_contents)
+ (TestJoinedTable.file_contents)
+ (TestLoadError.file_contents): Update for new DTD
+ (TestJoinedTable.file_contents, TestJoinedTable.setUp): Add test
+ for new join type attribute
+
+ * test/test_save.py (SaveSessionTest.dtd)
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer)
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table): Update for new DTD
+ (SaveSessionTest.test_joined_table): Add test for new join type
+ attribute
+
+2003-07-04 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (_find_dbf_column_names): New. Helper
+ function for table_to_dbf
+ (table_to_dbf): Deal with names longer than the 10 character limit
+
+ * test/test_dbf_table.py (TestTableToDBF.test_table_to_dbf): Add
+ doc-string
+ (TestTableToDBF.test_table_to_dbf_long_col_names): New test for
+ long column names
+
+2003-07-03 Bernhard Herzog <bh at intevation.de>
+
+ * Doc/manual/thuban-manual.xml: Fix the CVS Revision Tag syntax
+
+2003-07-03 Bernhard Herzog <bh at intevation.de>
+
+ * Doc/manual/thuban-manual.xml, Doc/manual/README: New. Skeleton
+ for the Thuban manual and README with some basic information about
+ the manual
+
+2003-07-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.__init__):
+ Update doc-string
+ (TransientJoinedTable.create): Do not modify the column objects of
+ the input tables in place and copy all columns of the input tables
+ into the joined table after all.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transient_joined_table_same_column_name):
+ Update to reflect the new behavior
+ (TestTransientTable.test_transient_joined_table_with_equal_column_names):
+ Update to reflect the new behavior
+ (TestTransientTable.test_transient_joined_table_name_collisions_dont_modify_in_place):
+ New test case for a bug which modified the column objects in place
+
+2003-07-02 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py (generate_singletons,
+ generate_uniform_distribution, generate_quantiles,
+ GenQuantiles0): Make sure maxValue isn't less than
+ one, otherwise we could divide by zero.
+
+ * test/test_classgen.py (ClassGenTest.doClassRangeTest,
+ ClassGenTest.doClassSingleTest): Call doBoundsTest to
+ check the end classification groups against the
+ proper property values.
+ (ClassGenTest.doBoundsTest): New. Checks the first and
+ last classification groups to make sure their properties
+ are the correct upper and lower bounds for a color ramp.
+
+2003-07-02 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py (generate_singletons,
+ generate_uniform_distribution, generate_quantiles,
+ GenQuantiles0): The denominator was one to high when
+ calculating the index for the ramp causing the index
+ to never to reach one.
+
+2003-07-02 Jonathan Coles <jonathan at intevation.de>
+
+ Changed the singature of ClassGroupRange.__init__ and
+ ClassGroupRange.SetRange() so that the min/max values are
+ passed as a tuple. This makes a better calling scheme for
+ when a Range object is passed instead.
+
+ * Thuban/Model/classgen.py: Fixed parameters to
+ ClassGroupRange constructor.
+
+ * Thuban/Model/classification.py (ClassGroupRange.__init__):
+ Consolidate the min/max parameters into a single _range which
+ can either be a tuple or a Range object.
+ (ClassGroupRange.SetRange): Consolidate the min/max parameters
+ into a single _range which can either be a tuple or a Range object.
+
+ * Thuban/Model/load.py (SessionLoader.start_clrange): Fix
+ call to ClassGroupRange constructor to use a tuple.
+
+ * Thuban/Model/layer.py (Layer.SetClassification): Switch
+ the classification instance variable to the new class
+ before calling _set_layer otherwise subscribers to a
+ LAYER_CHANGED event will not see any difference.
+
+ * test/test_classification.py: Fix tests of ClassGroupRange
+ so that they use the new signature.
+
+ * test/test_load.py: Fix use of ClassGroupRange so that it
+ uses the new signature.
+
+ * test/test_load_0_2.py: Fix use of ClassGroupRange so that it
+ uses the new signature.
+
+ * test/test_save.py: Fix use of ClassGroupRange so that it
+ uses the new signature.
+
+
+2003-07-01 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py: Fixes RTbug #1972, 1971.
+ Import used objects/class from color.
+ (generate_singletons): We don't
+ need the numGroups parameter anymore because we are using
+ the new ramps with GetProperties().
+ (generate_uniform_distribution): Use new ramp method
+ GetProperties().
+ (generate_quantiles, GenQuantiles0): Use new ramp method
+ GetProperties().
+ (CustomRamp.SetNumGroups): Removed. The ramps now map
+ a value from 0 to 1 to class properties so the number
+ of groups is not needed ahead of time.
+ (CustomRamp.next): Removed. CustomRamp does not support
+ interation anymore.
+ (CustomRamp.GetProperties): Returns a ClassGroupProperties
+ object based on the index value from 0 to 1 that is
+ passed to it.
+ (GreyRamp, RedRamp, GreenRamp, BlueRamp, GreenToRedRamp):
+ Made into instances of Monochromatic class instread of
+ deriving from it.
+ (HotToCold.SetNumGroups): Removed. See CustomRamp.
+ (HotToCold.next): Removed. See CustomRamp.
+
+ * Thuban/Model/classification.py: Fixes RTbug #1973, 1971.
+ (Classification.SetField, Classification.SetFieldType):
+ Replaced with SetFieldInfo.
+ (Classification.SetFieldInfo): New. Does a better job of
+ what SetField and SetFieldType used to do by combining
+ their function since they should really always be done
+ at the same time.
+ (Classification.SetLayer): Renamed to _set_layer.
+ (Classification._set_layer): Should only be called from
+ Layer's SetClassification. This does not cause a recursive
+ call as SetLayer did because we know that Layer knows about
+ the classification.
+
+ * Thuban/Model/color.py: Fixes RTbug #1971.
+ (_Transparent): Renamed from Transparent so it doesn't
+ conflict with the module variable.
+ (Transparent, Black): Renamed from Color.Transparent,
+ Color.Black so they are not class variables.
+
+ * Thuban/Model/layer.py: Fixes RTbug #1971, 1973.
+ (Layer.Destroy): We don't need to call SetClassification
+ anymore to clear out the back reference in the classifcation
+ to the layer. It's better to set it to None using _set_layer,
+ and we won't be creating another clas object too.
+ (Layer.SetClassification): Classification._set_layer is not
+ recursive so remove all the locking variables. Also clean
+ up the code so that it remains unchanged if something fails.
+
+ * Thuban/Model/load.py: Fixes RTbug #1971.
+ (SessionLoader.start_classification): Call
+ Classification.SetFieldInfo().
+
+ * Thuban/Model/save.py: Removed import of Color which wasn't
+ being used.
+
+ * Thuban/UI/classgen.py: Fixes RTbug #1972.
+ (ClassGenDialog.__init__): Color ramps are now instances
+ already so we don't need to create any new objects.
+ (ClassGenDialog.OnOK): Check for numGroups is no longer
+ necessary because we never use it.
+
+ * Thuban/UI/classifier.py: Fixes RTbug #1971.
+ (Classifier.__BuildClassification, Classifier.__SetGridTable):
+ Call Classification.SetFieldInfo() instead of SetFieldType.
+
+ * Thuban/UI/renderer.py: Fixes RTbug #1971.
+
+ * Thuban/UI/view.py: Fixes RTbug #1974, 1971.
+ (MapCanvas.__init__): Subscribe to the idle time event. Set
+ background color to white.
+ (MapCanvas.OnPaint): Set a flag indicating that we should
+ render the map during idle time. If we already have a bitmap
+ just draw it now.
+ (MapCanvas.OnIdle): New. Render the map only during idle time.
+ This also fixes a problem with the busy cursor under gtk.
+
+ * test/test_classgen.py (ClassGenTest.test_generate_singletons):
+ Fix calls to generate_singletons because the signature changed.
+
+ * test/test_classification.py: Fix color references and
+ change calls to Classification.[SetField|SetFieldType] to
+ SetFieldInfo.
+
+ * test/test_load.py: Fix color references.
+
+ * test/test_load_0_2.py: Fix color references.
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer):
+ Change calls to Classification.[SetField|SetFieldType] to
+ SetFieldInfo.
+
+2003-07-01 Frank Koormann <frank.koormann at intevation.de>
+
+ MERGE from the greater-ms3 branch.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transient_joined_table_with_equal_column_names):
+ New. Test join of two tables with partly equal column names.
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.create):
+ If duplicates in left and right tables column names are found,
+ append '_' (underscores) to the name until it is unique.
+ Create always new internal names for the resulting table and reference
+ columns in the join statement with <table>.<column>
+
+2003-07-01 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transient_joined_table_same_column_name):
+ New. Test whether joining on columns with the same names in both
+ tables works.
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.create): Make
+ sure to use the right internal names even when joining on field
+ with the same names in both tables. Also, detect duplicate names
+ in the joined table correctly.
+
+2003-07-01 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/renderer.py (ExportRenderer.render_legend):
+ Reverse List of layers to render in same order as in desktop legend.
+
+2003-06-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/version.py (make_tuple): Takes a version string
+ and splits it into a tuple of at most three integers.
+ Used make_tuple() to make tuple versions of the version
+ numbers.
+
+ * Thuban/UI/about.py: Add Thuban email addresses.
+
+2003-06-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/version.py: SQLite/PySQLite version dependencies
+ were too high.
+
+2003-06-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/version.py: Update version to 0.8.1
+
+ * MANIFEST.in: Added Projections so that default.proj is
+ included.
+
+2003-06-26 Jonathan Coles <jonathan at intevation.de>
+
+ New About box with lots more information including library
+ versions and credits. More/better version checking before
+ Thuban starts.
+
+ * Thuban/UI/about.py: New. New About box that displays
+ library version information and credits.
+
+ * Thuban/version.py: Added new 'versions' dictionary which
+ contains the verions of various libraries which are checked
+ when the module loads.
+ (verify_versions): Check all version numbers and returns
+ a list of errors.
+
+ * Thuban/UI/classifier.py (Classifier.__EnableButtons):
+ Reset the status of the buttons as the situation warrants,
+ but in a better more reliable way by not relying on the
+ current status to determine what needs to change.
+
+ * Thuban/UI/main.py (wxCHECK_VERSION): Removed. Not needed.
+ (verify_versions): Remove most of the code since it is
+ now in Thuban.version.verify_versions.o
+
+ * Thuban/UI/mainwindow.py (MainWindow.About): Call new
+ About box in Thuban.UI.about.
+
+ * extensions/thuban/gdalwarp.cpp (get_gdal_version): New.
+ Returns the version of gdal library being used as a string.
+
+ * extensions/thuban/wxproj.cpp (check_version, check_version_gtk):
+ Removed.
+ (get_proj_version): Return the version of PROJ that the file
+ was compiled with.
+ (get_gtk_version): Return th version of GTK that the file
+ was compiled with.
+
+2003-06-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier.EditSymbol): The parent
+ of the SelectPropertiesDialog should be self so the window
+ appears on top.
+ (ClassGroupPropertiesCtrl.DoEdit): The parent
+ of the SelectPropertiesDialog should be self so the window
+ appears on top.
+
+ * Thuban/UI/resource.py: Cleaned up how we determine file
+ extensions.
+ (GetImageResource): Return an wxImage from our Resources.
+
+2003-06-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/renderer.py (ExportRenderer.render_legend):
+ Check that a layer has a classification before trying
+ to get it. Raster layers don't have classifications.
+
+2003-06-23 Jonathan Coles <jonathan at intevation.de>
+
+ * setup.py: Add Resources/XML to resource list.
+
+2003-06-23 Jonathan Coles <jonathan at intevation.de>
+
+ * setup.cfg: Fix copyright dates
+
+2003-06-23 Jonathan Coles <jonathan at intevation.de>
+
+ * MANIFEST.in: Update with Resources/XML
+
+ * setup.py: Don't include Locale resources yet as we don't
+ have any and it causes problems building the distribution
+ for Windows. Update version to 0.8.0.
+
+ * Doc/thuban.dtd: Removed since it is now in Resources/XML.
+
+ * Thuban/UI/mainwindow.py: Add blank line at the end because
+ file was not being read correctly building the Windows
+ distribution.
+
+2003-06-23 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.About): Fix text.
+
+ * Thuban/version.py: Temporarily update longversion for
+ the 0.8 release so that it doesn't have the cvs revision.
+
+2003-06-23 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/common.py (ThubanBeginBusyCursor): Call wxSafeYield
+ to make sure that we don't create reentrant possibilities with
+ wxYield.
+
+ * Thuban/UI/view.py (MapCanvas.OnPaint): Call wxBeginBusyCursor()
+ directly to avoid the wxSafeYield() call which generates an
+ OnPaint event causing infinite recursion. Don't try to catch
+ exception anymore. This was for before there were limits on map
+ scaling.
+
+2003-06-23 Bernhard Herzog <bh at intevation.de>
+
+ Bug fix for RT #1961:
+
+ * Thuban/Model/load.py (SessionLoader.start_derivedshapesource):
+ Register DerivedShapestores with the session
+
+ * Thuban/Model/session.py (Session.Tables): Make sure each table
+ is only listed once.
+
+ * test/test_load.py (TestJoinedTable.test): Add check_format call.
+ Update file contents to match the one written out.
+
+2003-06-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/xmlsupport.py (SaxEventLister.startElementNS)
+ (SaxEventLister.endElementNS): Do not include the qname. Python
+ 2.2.1 and 2.2.2 and 2.2.3 differ in this regard. In 2.2.1 qname it
+ is (presumably incorrectly) None, whereas it's a string with the
+ element name in the later versions.
+
+ * test/test_xmlsupport.py (TestEventList.test_even_list_simple)
+ (TestEventList.test_even_list_namespace): Update tests to reflect
+ the new behaviour
+ (TestEventList.test_even_list_id_normalization): Fix doc-string
+
+2003-06-20 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/layer.py (BaseLayer.HasShapes): New. Overridden
+ by deriving classes to determine if that layer supports shapes.
+ (Layer): Override HasShapes and return true.
+
+ * Thuban/UI/classgen.py: Use Thuban[Begin|End]BusyCursor()
+ instead of a direct call to wx[Begin|End]CusyCursor().
+ (GenUniquePanel._OnRetrieve): Set busy cursor while retrieving
+ table data.
+
+ * Thuban/UI/common.py (ThubanBeginBusyCursor, ThubanEndBusyCursor):
+ New. Wrappers around the wxWindows functions that allow us to
+ make additional calls such as wxYield which gives the native
+ system a chance to update the cursor correctly.
+
+ * Thuban/UI/tableview.py: Use Thuban[Begin|End]BusyCursor()
+ instead of a direct call to wx[Begin|End]CusyCursor().
+
+ * Thuban/UI/view.py: Use Thuban[Begin|End]BusyCursor()
+ instead of a direct call to wx[Begin|End]CusyCursor().
+ (MapCanvas.find_shape_at): Check if the current search layer
+ support shapes, otherwise go on to the next layer.
+
+ * test/test_layer.py: Add tests in each type of layer for
+ HasClassification() and HasShapes()
+
+2003-06-20 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.OnPaint): Call wxYield after
+ turning on the busy cursor to allow the system to change the
+ cursor before we begin painting. This fixes a problem that
+ was occuring only under GTK. Fixes RTbug #1840.
+
+2003-06-20 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/XML/thuban-0.8.dtd: New DTD for the new file format
+ version.
+
+ * Thuban/Model/save.py (sort_data_stores): New. Make topological
+ sort of the data sources so they can be written with sources that
+ data sources that depend on other data sources come after the
+ sources they depend on.
+ (SessionSaver.__init__): Add idmap instance variable to map from
+ objects to the ids used in the file.
+ (SessionSaver.get_id, SessionSaver.define_id)
+ (SessionSaver.has_id): New. Methods to manage the idmap
+ (SessionSaver.write): Use thuban-0.8.dtd
+ (SessionSaver.write_session): Add a namespace on the session and
+ write out the data sources before the maps.
+ (SessionSaver.write_data_containers): New. Write the data
+ containers.
+ (SessionSaver.write_layer): Layer elements now refer to a
+ shapestore and don't contain filenames anymore.
+
+ * Thuban/Model/load.py (LoadError): Exception class to raise when
+ errors in the files are discovered
+ (SessionLoader.__init__): Define dispatchers for elements with a
+ thuban-0.8 namespace too.
+ (SessionLoader.check_attrs): New helper method to check and
+ convert attributes
+ (AttrDesc): New. Helper class for SessionLoader.check_attrs
+ (SessionLoader.start_fileshapesource)
+ (SessionLoader.start_derivedshapesource)
+ (SessionLoader.start_filetable, SessionLoader.start_jointable):
+ Handlers for the new elements in the new fileformat
+ (SessionLoader.start_layer): Handle the shapestore attribute in
+ addition to filename.
+ (SessionLoader.start_table, SessionLoader.end_table): Removed.
+ They were never used in the old formats and aren't needed for the
+ new.
+
+ * Thuban/Model/session.py (Session.DataContainers): New method to
+ return all "data containers", i.e. shapestores and tables
+
+ * test/xmlsupport.py (SaxEventLister.__init__)
+ (SaxEventLister.startElementNS, sax_eventlist): Add support to
+ normalize IDs.
+
+ * test/test_xmlsupport.py
+ (TestEventList.test_even_list_id_normalization): New test case for
+ id normalization
+
+ * test/test_load.py (LoadSessionTest.check_format): Use ID
+ normalization
+ (LoadSessionTest.thubanids, LoadSessionTest.thubanidrefs): New
+ class atrributes used for ID normalization
+ (TestSingleLayer, TestLayerVisibility, TestLabels.test)
+ (TestLayerProjection.test, TestRasterLayer.test): Adapt to new
+ file format
+ (TestJoinedTable): New test for loading sessions with joined
+ tables.
+ (TestLoadError): New. Test whether missing required attributes
+ cause a LoadError.
+
+ * test/test_save.py (SaveSessionTest.thubanids)
+ (SaveSessionTest.thubanidrefs): New class attributes for ID
+ normalization in .thuban files.
+ (SaveSessionTest.compare_xml): Use id-normalization.
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer): Adapt to new file format.
+ (SaveSessionTest.testLayerProjection): The filename used was the
+ same as for testSingleLayer. Use a different one.
+ (SaveSessionTest.test_dbf_table)
+ (SaveSessionTest.test_joined_table): New test cases for saving the
+ new data sources structures.
+ (TestStoreSort, MockDataStore): Classes to test the sorting of the
+ data stores for writing.
+
+ * test/runtests.py: Add CVS keywords
+
+2003-06-20 Jonathan Coles <jonathan at intevation.de>
+
+ * test/test_session.py
+ (UnreferencedTablesTests.test_unreferenced_tables_with_joins):
+ Use the cultural_landmark-point.dbf file for the store so that
+ the table rows and shape count match.
+
+2003-06-20 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/data.py (DerivedShapeStore.__init__): Raise
+ an exception if the number of shapes is different from the
+ number of rows in the table. Address RTbug #1933.
+
+ * test/test_layer.py (TestLayer.test_derived_store): Add
+ a test for the new exception in DerivedShapeStore.__init__.
+
+ * test/support.py (FloatTestCase): Removed since there is
+ already FloatComparisonMixin. Fixes RTbug #1954.
+ (FloatComparisonMixin.assertFloatEqual): Include test for
+ infinity that was part of FloatTestCase.
+
+ * test/test_range.py (RangeTest): Inherit from
+ support.FloatComparisonMixin now that we don't have
+ support.FloatTestCase.
+
+2003-06-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_save.py (SaxEventLister, sax_eventlist): Removed. Use
+ the implementation in xmlsupport instead.
+ (SaveSessionTest.compare_xml): sax_eventlist is now in xmlsupport
+
+ * test/test_proj.py: Import sax_eventlist from xmlsupport instead
+ of test_save
+
+2003-06-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_load.py (LoadSessionTest.check_format): New helper
+ method to make sure the test files we load might have been written
+ by the current thuban version.
+ (ClassificationTest.TestLayers, TestSingleLayer.test)
+ (TestLayerVisibility.test, TestClassification.test)
+ (TestLabels.test, TestLayerProjection.test, TestRasterLayer.test):
+ Add check_format() calls and fix the thuban data to match the data
+ that would be written by saving the session loaded from it.
+
+ * test/xmlsupport.py (SaxEventLister, sax_eventlist): Copies of
+ the same class and function in test_save.
+
+ * test/test_xmlsupport.py (TestEventList): New. test cases for
+ sax_eventlist
+
+2003-06-20 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/XML/thuban.dtd: Add comment about which versions of
+ Thuban are covered by this DTD
+ (map): Fix content model for layers and raster layers. There can
+ be any number or layers and raster layers in any order.
+
+2003-06-20 Jonathan Coles <jonathan at intevation.de>
+
+ This is mainly about fixing RTbug #1949.
+
+ * Thuban/Model/classification.py: Remove "from __future__"
+ import statement since python 2.2 is the earliest supported
+ version.
+
+ * Thuban/Model/proj.py (Projection.GetProjectedUnits): New.
+ Currently returns PROJ_UNITS_METERS or PROJ_UNITS_DEGREES
+ depending on the units this projection *forwards* into.
+
+ * Thuban/Model/save.py (SessionSaver.write_classification):
+ Remove unnecessary use of lambdas and nested functions.
+
+ * Thuban/UI/legend.py (ScaleBarBitmap.__SetScale): Do scale
+ adjustment here if the map projection uses degrees.
+
+ * Thuban/UI/scalebar.py (ScaleBar.DrawScaleBar): Remove
+ scale adjust code since it is now done before calling
+ this method. Don't do anything if the map projection
+ is None.
+
+2003-06-19 Bernhard Herzog <bh at intevation.de>
+
+ Move version specific load tests to their own file.
+
+ * test/test_load.py: Expand the doc-string to explain a bit how to
+ handle file format changes.
+ (TestClassification.test): Update the docstring as this test is
+ not about Thuban 0.2 anymore.
+
+ * test/test_load_0_2.py: New file with the load tests for thuban
+ files created with Thuban 0.2 and earlier.
+
+2003-06-19 Bernhard Herzog <bh at intevation.de>
+
+ Add XML validation to some of the tests. Validation will only be
+ done if pyRXP is installed (http://reportlab.com/xml/pyrxp.html).
+ To make the DTD available to the test cases it's moved into
+ Resources/XML
+
+ * Resources/XML/thuban.dtd: New. This is now the real Thuban DTD
+ for versions up to and including 0.2. Two slight changes: added an
+ encoding specification and fixed the comment which refered to
+ GRASS, not Thuban
+
+ * test/xmlsupport.py: New support module for tests involving XML.
+ Currently there's a mix-in class for XML validation.
+
+ * test/test_xmlsupport.py: New. Tests for the xmlsupport module
+
+ * test/test_save.py (SaveSessionTest): Derive from ValidationTest
+ so that we can validate the
+ (SaveSessionTest.testEmptySession)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testSingleLayer)
+ (SaveSessionTest.testLayerProjection)
+ (SaveSessionTest.testRasterLayer)
+ (SaveSessionTest.testClassifiedLayer): Validate the generated XML
+
+ * test/runtests.py (main): Call print_additional_summary instead
+ of print_garbage_information
+
+ * test/support.py (resource_dir): New function to return the
+ "Resource" subdirectory
+ (print_additional_summary): New function to combine several
+ summary functions
+ (run_tests): Use print_additional_summary instead of calling
+ print_garbage_information directly
+
+2003-06-19 Bernhard Herzog <bh at intevation.de>
+
+ * Doc/thuban.dtd (classification): Correct the content model of
+ the classification element.
+ (projection): Add the "name" attribute
+
+2003-06-19 Frank Koormann <frank.koormann at intevation.de>
+
+ MERGE from the greater-ms3 branch.
+
+ * Thuban/UI/scalebar.py (ScaleBar.DrawScaleBar): Apply conversion to
+ scale if projection is latlong to get better estimate.
+
+ Fix problem of hidden properties dialog under windows after double
+ click on layer tree:
+ The tree control always gets an Expanded / Collapsed event after
+ the ItemActivated on double click, which raises the main window again.
+ We add a second ItemActivated event to the queue, which simply
+ raises the already displayed window.
+
+ * Thuban/UI/legend.py (LegendTree.__init__): Instance variable
+ raiseProperties initialized to prevent endless loops
+ (LegendTree._OnItemActivated): Depending on self.raiseProperties
+ simply raise the properties or open the dialog and issue a second
+ event.
+
+2003-06-18 Jonathan Coles <jonathan at intevation.de>
+
+ * setup.py: Fix a few problems that occured under Windows.
+
+2003-06-18 Jonathan Coles <jonathan at intevation.de>
+
+ When Thuban loaded the map was redrawn twice because the
+ legend was being opened after the mainwindow was created
+ and not during its creation. This meant the map was drawn
+ initially and then had to be redrawn when the legend
+ caused the display to change. Now the legend is opened
+ in the mainwindow constructor which resolves this issue.
+
+ Also, although we were checking for the existence of
+ gdal and gdalwarp modules, the gdalwarp extension was
+ still being compiled (which may fail if the system doesn't
+ have gdal installed). the build_ext command to setup.py
+ now accepts the flags --with-gdal and --without-gdal.
+ If --without-gdal is specified setup.py will try to
+ use the gdal parameters specified by gdal-config. Under
+ windows, those parameters have to be set in setup.py
+ as with proj4 an wxWindows.
+
+ * setup.py: Use a list instead of seperate variables for
+ extension parameters so we can create a generic function
+ that runs an appropriate *-config script.
+ (run_cs_script): Renamed from run_wx_script and modified
+ to accept a second argument which is a list of lists to
+ be filled in by the values returned from running the command.
+ (thuban_build_ext): New. Extends the build_ext command and
+ provides the options --with-gdal/--without-gdal which then
+ optionally includes the gdalwarp extension.
+
+ * Thuban/Model/resource.py: First check if we can import
+ the gdalwarp Thuban extension before checking for gdal.
+ Also added some comments.
+
+ * Thuban/UI/legend.py (ScaleBarBitmap.__SetScale): Check if
+ the map is None which may be the case if none has been loaded
+ yet.
+
+ * Thuban/UI/main.py (main): Remove call to ShowLegend.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Call ShowLegend().
+
+ * Thuban/UI/renderer.py: Check for gdal support before importing
+ gdalwarp.
+ (MapRenderer.render_map): Only try to optimize if we have gdal
+ support otherwise nothing will get drawn.
+
+ * Thuban/UI/view.py (MapCanvas.FitMapToWindow): This may be called
+ during startup before a map has been created. Check if map is None
+ before using it and do nothing if it is.
+
+2003-06-17 Jonathan Coles <jonathan at intevation.de>
+
+ Fix the problem with raster layers under Windows that caused
+ Thuban to crash. The view should respond to layer projection
+ changed events to update the display. Changes to a projection
+ should not cause the map to be set to full extent.
+
+ * Thuban/UI/view.py (MapCanvas.__init__): New instance variable
+ current_map_proj to remember the current map projection so that
+ when the projection changes we know what the previous projection
+ was.
+ (MapCanvas.SetMap): Unsubscribe and subscribe to
+ LAYER_PROJECTION_CHANGED events.
+ (MapCanvas.projection_changed): Split into two methods that respond
+ to map and layer projection changes.
+ (MapCanvas.map_projection_changed): New. Takes the current view and
+ projects it using the new projection. This does not cause the
+ map to be redrawn at full extent.
+ (MapCanvas.layer_projection_changed): New. Cause a redraw which
+ will draw each layer in its new projection.
+
+ * extensions/thuban/bmpdataset.cpp (BMPDataset::Open): Call
+ VSIFClose() not VSIFCloseL() to close the file. Fixes a crash
+ under Windows.
+
+ * extensions/thuban/gdalwarp.cpp (MFILENAME): Padding should be
+ to twice sizeof(void*) because there are two digits for each
+ hex byte.
+
+2003-06-16 Bernhard Herzog <bh at intevation.de>
+
+ Update to the layer interface: Direct access to the table,
+ shapetable, shapefile and filename attributes is now actively
+ deprecated by issuing deprecation warnings for all places where
+ this happens.
+
+ * Thuban/Model/layer.py (Layer.__getattr__): New. Implement access
+ to the instance variables table, shapetable, shapefile and
+ filename via __getattr__ so that we can issue a deprecation
+ warning.
+ (Layer.SetShapeStore): Don't set the deprecated instance variables
+ any more
+ (Layer.SetShapeStore): Don't use deprecated layer instance
+ variables
+ (Layer.Destroy): No need to explicitly remove the instance
+ variables any more
+ (Layer.GetFieldType, Layer.Shape): Don't use deprecated layer
+ instance variables
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__)
+ (GenUniformPanel._OnRetrieve, GenUniquePanel._OnRetrieve)
+ (GenQuantilesPanel.GetList, GenQuantilesPanel.OnRetrieve): Don't
+ use deprecated layer instance variables
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Don't use
+ deprecated layer instance variables
+
+ * Thuban/UI/identifyview.py (IdentifyListCtrl.selected_shape)
+ (IdentifyGridCtrl.selected_shape): Don't set the deprecated layer
+ instance variables
+
+ * Thuban/UI/tableview.py (LayerTableGrid.select_shapes): Don't use
+ deprecated layer instance variables
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Don't use
+ deprecated layer instance variables
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Don't use
+ deprecated layer instance variables
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer)
+ (MapRenderer.polygon_render_param): Don't use deprecated layer instance
+ variables
+
+ * test/runtests.py (main): Turn Thuban's deprecation warnings into
+ errors so that they're cought by the tests
+
+ * test/test_load.py (TestSingleLayer.test): Don't use deprecated
+ layer instance variables
+
+2003-06-16 Jonathan Coles <jonathan at intevation.de>
+
+ Fix a problem under Windows whereby if the user double-clicks on a
+ layer in the legend that tree item will expand or collapse as well
+ as open the layer properties dialog. The state of the tree item
+ should not be affected.
+
+ * Thuban/UI/legend.py (LegendTree.__init__): Add instance variable
+ preventExpandCollapse and subscribe to expanding and collapsing
+ events.
+ (LegendTree.OnItemExpandCollapse): New. Responds to expanding and
+ collapsing events and will veto the event if it has been triggered
+ by the user double clicking on a layer.
+ (LegendTree._OnItemActivated): Set preventExpandCollapse to indicate
+ that an expanding/collapsing event should be vetoed.
+
+2003-06-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier.OnClose)
+ (Classifier.map_layers_removed)
+ (Classifier.layer_shapestore_replaced): Unsubscribe the messages
+ in OnClose and not in map_layers_removed or
+ layer_shapestore_replaced to make sure it always happens when the
+ dialog is closed
+
+2003-06-13 Jonathan Coles <jonathan at intevation.de>
+
+ This puts back a fix for Windows where a panel is needed so that
+ the background of the table view appears correctly.
+
+ * Thuban/UI/tableview.py (TableFrame.__init__): Add a panel
+ object that can be used by derived classes to place any
+ controls (including the grid) onto.
+ (QueryTableFrame.__init__): Use the panel as the parent window
+ for all the controls. Reparent the grid so that the panel is
+ the parent. Call UpdateStatusText() to correctly initialize
+ the status bar.
+
+2003-06-13 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/dialogs.py (ThubanFrame): New: a class that inherits
+ from wxFrame (as opposed to wxDialog like the other classes)
+ but otherwise behaves like the other classes. This is needed
+ for the TableView which isn't really a dialog and needs to
+ have a status bar and control buttons.
+
+ * Thuban/UI/tableview.py (TableGrid.__init__): Create an
+ instance variable to keep track of how many rows are selected.
+ Subscribe once to the the events we are interested in.
+ (ThubanGrid.OnRangeSelect): Only handle event if event handling
+ hasn't been turned off.
+ (ThubanGrid.OnSelectCell): Only handle event if event handling
+ hasn't been turned off.
+ (ThubanGrid.ToggleEventListeners): Rather than subscribe None
+ as an event listener (which changes the event handler stack)
+ simply set an instance variable to False. This is checked in
+ the event handlers.
+ (ThubanGrid.GetNumberSelected): Return the number of currently
+ selected rows.
+ (TableFrame): Inherit from ThubanFrame so we can have a
+ status bar and control buttons.
+ (QueryTableFrame.__init__): Create a status bar. Fixes RTbug #1942.
+ Explicitly set which items are selected in the operator choice and
+ action choice so there is always a valid selection. Fixes RTbug #1941.
+ Subscribe to grid cell selection events so we can update the
+ status bar.
+ (QueryTableFrame.UpdateStatusText): Update the status bar with
+ how many rows are in the grid, how many columns, and how many
+ rows are selected.
+ (QueryTableFrame.OnGridSelectRange, QueryTableFrame.OnGridSelectCell):
+ Call UpdateStatusText when cells are (de)selected.
+ (QueryTableFrame.OnQuery): Use the string value in the value
+ combo if either the selected item index is 0 or if the string
+ cannot be found in the predefined list (this happens if the
+ user changes the text). Fixes RTbug #1940.
+ Only turn off the grid event listeners if there a query comes
+ back with a none empty list of ids. in the case that the list
+ is empty this causes a grid.ClearSelection() call to actually
+ clear the grid selection which causes the selected items in
+ the map to be deselected. Fixes RTbug #1939.
+
+ * test/test_save.py (XMLWriterTest.Encode): Check return values.
+ Fixes RTbug #1851.
+
+2003-06-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyView.__init__): Call
+ self.selected_shape with the current selection to make sure the
+ contents of the dialog are up to date when it's shown for the
+ first time.
+ The dialog used to work without this by luck. The recent fix to
+ the connector module 'broke' a 'feature' the identify view was
+ relying on, i.e that subscribing to a message in response to
+ receiving a message of that type would mean that the new
+ subscriber would also be called for the same message.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * extensions/thuban/gdalwarp.cpp: Removed debug printing as
+ the image is rendered. Fixes RTbug #1937.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Lib/fileutil.py: As is done under Windows, create the
+ user directory if it doesn't exist on a posix system.
+ Fixes RTbug #1815.
+
+ * Thuban/Model/resource.py (get_user_proj_files): Moved the
+ called to get_application_dir here, so that the directory
+ will only be called if this method is invoked.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__DoOnProjAvail): Clear
+ the projfilepath if no projection is selected.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/legend.py (ScaleBarBitmap.__SetScale): Don't draw
+ the scalebar if the current map has no projection set.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__DoOnProjAvail): Set the
+ projfilepath label to just the basename of the projection file
+ rather than include the entire path.
+
+ * Thuban/Model/resource.py: Fix missed proj functions that
+ needed to be renamed.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Removed assert statements that
+ tested if the variable was an instance of Color.
+
+ * Thuban/Model/color.py (Color): Remove commented code that isn't
+ used.
+ (Transparent): Renamed from NoColor. Doesn't inherit from Color.
+ Fixes RTbug #1835.
+ (Transparent.__eq__, Transparent.__ne, Transparent.__repr): New.
+ Needed now that the class doesn't inherit from Color.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * test/test_save.py (XMLWriterTest.testEncode): Explicitly
+ check unicode strings.
+
+ * test/test_layer.py: Check for existence of gdal.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/xmlreader.py: New. Contains the XMLReader class
+ that was in load.py
+
+ * Thuban/Model/xmlwriter.py: New. Contains the XMLWriter class
+ that was in save.py
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ This is largely a collection of bug fixes. We also handle the
+ case where gdal is not on the system. The XMLReader and XMLWriter
+ classes were moved into there own files to resolve some circular
+ import references and because they shouldn't really be in the
+ file that is dediciated to reading/writing session files since
+ they are also used elsewhere.
+
+ * Thuban/Model/classgen.py: Renamed functions to follow the
+ function_names_with_underscores style. Fixes RTbug #1903.
+ (calculate_quantiles): Raise ValueError if 'percents' is invalid.
+
+ * Thuban/Model/layer.py: Import gdal only if it available.
+ (RasterLayer): Handle the case where the gdal library is unavailable.
+ Addresses RTbug #1877.
+
+ * Thuban/Model/load.py (XMLReader): Moved into seperate file
+ xmlreader.py.
+
+2003-06-12 Jonathan Coles <jonathan at intevation.de>
+
+ This is largely a collection of bug fixes. We also handle the
+ case where gdal is not on the system. The XMLReader and XMLWriter
+ classes were moved into there own files to resolve some circular
+ import references and because they shouldn't really be in the
+ file that is dediciated to reading/writing session files since
+ they are also used elsewhere.
+
+ * Thuban/Model/classgen.py: Renamed functions to follow the
+ function_names_with_underscores style. Fixes RTbug #1903.
+ (calculate_quantiles): Raise ValueError if 'percents' is invalid.
+
+ * Thuban/Model/layer.py: Import gdal only if it available.
+ (RasterLayer): Handle the case where the gdal library is unavailable.
+ Addresses RTbug #1877.
+
+ * Thuban/Model/load.py (XMLReader): Moved into seperate file
+ xmlreader.py.
+
+ * Thuban/Model/save.py (escape, XMLWriter): Moved into seperate
+ file xmlwriter.py.
+
+ * Thuban/Model/resource.py: Renamed functions to following the
+ function_names_with_underscores style.
+ (has_gdal_support): New function that returns true if the gdal
+ library is available. Addresses RTbug #1877.
+
+ * Thuban/UI/application.py (ThubanApplication.OpenSession):
+ Display a message box if the gdal library is not available, but
+ only if there are any layers that would use it. Addresses RTbug #1877.
+
+ * Thuban/UI/classgen.py: Use renamed projection resource functions.
+ (GenUniformPanel.__CalcStepping): Fix a slight discrepency
+ when using integers versus floats.
+
+ * Thuban/UI/mainwindow.py (_has_gdal_support): New. Used to
+ determine if the "Add Image Layer" menu option should be
+ greyed out or not. Addresses RTbug #1877.
+
+ * Thuban/UI/projdialog.py: Use renamed projection resource functions.
+
+ * Thuban/UI/renderer.py (MapRenderer.render_map): Only try to
+ optimize if a raster layer is visible. Fixes RTbug #1931.
+ Only draw the raster layer if the gdal library is available.
+ Addresses RTbug #1877.
+
+ * test/test_classgen.py: Add tests for generate_singletons,
+ generate_uniform_distribution, generate_quantiles. Fixes RTbug #1903.
+ (test_calculate_quantiles): Fix some tests to catch the new
+ ValueError that is raised.
+
+ * test/test_proj.py: Use renamed projection resource functions.
+
+ * test/test_save.py (SaveSessionTest.testClassifiedLayer): New
+ test for saving classified layers. Fixes RTbug #1902.
+ (XMLWriterTest): New. Tests the XMLWriter class. Fixes RTbug #1851.
+
+2003-06-12 Jan-Oliver Wagner <jan at intevation.de>
+
+ Fix for http://intevation.de/rt/webrt?serial_num=1900.
+
+ * Thuban/UI/multiplechoicedialog.py: New. A multiple choice dialog.
+
+ * Thuban/UI/mainwindow.py: import wxMultipleChoiceDialog from
+ multiplechoicedialog.py rather than from the wxPython library.
+
+2003-06-11 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/Lib/fileutil.py (get_application_dir): Minor stability
+ update.
+
+2003-06-11 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/Lib/fileutil.py (get_application_dir): New function to
+ determine the absolute .thuban/thuban directory under
+ "posix" (os.expanduser) and "nt" (read AppData registry key).
+
+ * Thuban/Model/resource.py: Use get_application_dir
+
+ * Thuban/UI/application.py (ThubanApplication.read_startup_files):
+ Use get_application_dir.
+
+2003-06-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tableview.py (LayerTableFrame.__init__): Subscribe to
+ the messages MAP_LAYERS_REMOVED messages
+ (LayerTableFrame.OnClose): Unsubscribe from it.
+ (LayerTableFrame.map_layers_removed): New. Receiver for
+ MAP_LAYERS_REMOVED. Close the dialog when the layer whose the
+ dialog is showing is removed.
+
+2003-06-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Lib/connector.py (Connector.Issue): Iterate over a copy
+ of the receivers list so that unsubscribing in a receiver doesn't
+ modify it while iterating over it.
+
+ * test/test_connector.py
+ (ConnectorTest.test_disconnect_in_receiver): New. Test whether
+ unsubscribing in a receiver works correctly. See docstring for
+ details
+
+2003-06-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/messages.py (LAYER_SHAPESTORE_REPLACED): New
+ message.
+
+ * Thuban/Model/layer.py (Layer.SetShapeStore): Send
+ LAYER_SHAPESTORE_REPLACED when the shapestore changes. A
+ LAYER_CHANGED will still be sent if the classification changes.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Add the map as
+ parameter so we can subscribe to some of its messages
+ (Classifier.__init__): Subscribe to the map's MAP_LAYERS_REMOVED
+ and the layer's LAYER_SHAPESTORE_REPLACED
+ (Classifier.unsubscribe_messages): New. Unsubscribe from message
+ subscribed to in __init__
+ (Classifier.map_layers_removed)
+ (Classifier.layer_shapestore_replaced): receivers for the messages
+ subscribed to in __init__. Unsubscribe and close the dialog
+
+ * Thuban/UI/mainwindow.py (MainWindow.OpenLayerProperties): Pass
+ the map to the Classifier dialog
+
+ * test/test_layer.py (SetShapeStoreTests): Derive from
+ SubscriberMixin as well so we can test messages
+ (SetShapeStoreTests.setUp): Subscribe to some of the layer's
+ messages
+ (SetShapeStoreTests.tearDown): Clear the messages again
+ (SetShapeStoreTests.test_sanity): Expand the doc-string and check
+ for the modified flag too
+ (SetShapeStoreTests.test_set_shape_store_modified_flag): New test
+ to check whether SetShapeStore sets the modified flag
+ (SetShapeStoreTests.test_set_shape_store_different_field_name)
+ (SetShapeStoreTests.test_set_shape_store_same_field)
+ (SetShapeStoreTests.test_set_shape_store_same_field_different_type):
+ Add tests for the messages. This checks both the new
+ LAYER_SHAPESTORE_REPLACED and the older LAYER_CHANGED
+
+2003-06-06 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Improved and partly added help texts for
+ the menu items.
+
+2003-06-05 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyView.__init__):
+ Layout reimplemented without panel. Make life easier to fit the list
+ in the dialog.
+
+2003-06-05 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__): Fill the projchoice
+ once on initialisation (Former implementation resulted in multiple
+ entries for each projection).
+ (ProjFrame.__FillAvailList): selectProj as second optional parameter,
+ if set, select the projection found under the specified name. This
+ overwrites any other selection estimate.
+ Removed projchoice filling from this method.
+ (ProjFrame._OnSave, ProjFrame._OnAddToList):
+ Updated call of ProjFrame.__FillAvailList
+ (LCCPanel._DoLayout): Moved parameter controls in more common order.
+
+ * Resources/Projections/defaults.proj: Extended defaults representing
+ various common European projections.
+
+2003-06-05 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyView.__init__):
+ Use ListCtrl instead of GridCtrl
+
+ * Thuban/Model/resource.py:
+ Guess location of .thuban directory from tempdir parent directory.
+
+ * Thuban/UI/application.py (ThubanApplication.read_startup_files):
+ Guess location of .thuban directory from tempdir parent directory.
+
+2003-06-04 Bernhard Herzog <bh at intevation.de>
+
+ Do not cache the values returned by the tree widget's
+ GetFirstChild and GetNextChild methods because it led to lots of
+ segfaults. The new way requires more brute force but is more
+ reliable.
+
+ * Thuban/UI/legend.py (LegendTree.__init__): Remove instance
+ variable layer2id
+ (LegendTree.find_layer): New method to do with brute force what
+ layer2id tried to accomplish
+ (LegendTree._OnMsgLayerChanged)
+ (LegendTree._OnMsgLayerTitleChanged, LegendTree.__ShowHideLayer):
+ Use find_layer instead of layer2id
+ (LegendTree.__RemoveLayer, LegendTree.__AddLayer): No need to
+ update layer2id anymore
+ (LegendTree._OnMsgMapLayersRemoved)
+ (LegendTree._OnMsgMapLayersAdded): Get by without layer2id.
+
+2003-06-03 Thomas Koester <tkoester at intevation.de>
+
+ * Thuban/Model/classgen.py (GenQuantiles0): New function.
+
+2003-06-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (layer_rename command, table_rename command):
+ New commands.
+ (main_menu): Add the new commands.
+ (MainWindow.TableRename): New. Implementation of the table_rename
+ command.
+ (MainWindow.RenameLayer): New. Implementation of the layer_rename
+ command.
+
+ * Thuban/Model/session.py (Session.AddTable): call self.changed to
+ set the modified flag
+
+ * test/test_session.py (TestSessionSimple.test_add_table): Test
+ whether the modified flag is set properly
+
+ * Thuban/Model/base.py (TitledObject.SetTitle): Call changed
+ instead of issue so that the modified flags get updated.
+
+ * test/test_base.py (SomeTitledObject): Derive from Modifiable
+ instead of Publisher to reflect reality better and to accomodate
+ the fact that SetTitle now calls changed instead of issue
+
+2003-06-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.GetList): Resource
+ acquisition has to happen before the try in a try-finally.
+
+2003-06-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/legend.py (LegendTree._OnMsgMapLayersRemoved): It's
+ possible that a layer is removed that is not currently selected in
+ the legend so don't check for this.
+
+2003-05-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.Destroy): Set all instance
+ variables to None that have direct or indirect references to
+ shapefiles or dbf files to make sure that they do go away and the
+ files are closed.
+
+2003-05-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/legend.py (LegendTree.GetRootItem): Reset
+ availImgListIndices when a new image list is created
+
+2003-05-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/legend.py (LegendTree.__init__): New instance variable
+ changing_selection to indicate whether the LegendTree code itself
+ is currently changing the selection
+ (LegendTree.normalize_selection): New method to normalize the
+ selection by selecting the layer item even if the user clicked on
+ the classification.
+ (LegendTree._OnSelChanged): normalize the selection. This works
+ around a bug in wx which doesn't keep track of the selection
+ properly when subtrees are deleted.
+
+2003-05-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.set_view_transform): Limit the
+ maximum and minimum scale factors.
+
+ * test/test_classgen.py (ClassGenTest.test): Update to reflect the
+ changes in classgen.py
+
+2003-05-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py: Remove ClassGenerator class but make
+ all the methods functions. Fixes RTBug #1903.
+
+ * Thuban/Model/map.py (Map.TopLayer, Map.BottomLayer): Renamed
+ to MoveLayerToTop and MoveLayerToBottom respectively. Fixes
+ RTBug #1907.
+
+ * Thuban/UI/classgen.py: Use classgen functions that were part
+ of the ClassGenerator class. Put try/finally blocks around
+ code that uses wxBeginBusyCursor()/wxEndBusyCursor(). Fixes
+ RTBug #1904.
+
+ * Thuban/UI/classifier.py: Remove unused import of ClassGenerator.
+
+ * Thuban/UI/legend.py: The legend was cleared and repopulated any
+ time something changed which caused some state to be lost such
+ as which children were expanded or collapsed. Fixes RTBug #1901.
+ (LegendTree._OnMsgMapLayersAdded): Add only new layers.
+ (LegendTree.__OnMsgMapLayersRemoved): Remove layers that exist in
+ the legend but not in the map.
+ (LegendTree.__FillTree): Move main functionality out into smaller
+ methods that can be used by other methods.
+ (LegendTree.__FillTreeLayer): Reuse old slots in the image list
+ if they are available.
+ (LegendTree.DeleteAllItems): Renamed from __DeleteAllItems so
+ that we override the wxTreeCtrl method. Iterate over children
+ and call __RemoveLayer.
+ (LegendTree.__AddLayer): New. Add a new layer to the legend.
+ (LegendTree.__RemoveLayer): Remove a layer from the legend.
+ (LegendTree.DeleteChildren): New, overrides wxTreeCtrl method.
+ Should only be called with the id of a layer branch.
+ (LegendTree.GetRootItem): New, overrides wxTreeCtrl method.
+ Returns the root item or creates one if necessary.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_raster_layer): Call
+ ProjectRasterFile with tuple arguments instead of strings.
+
+ * Thuban/UI/tableview.py (QueryTableFrame.OnQuery): Wrap code
+ with try/finally. Fixes RTBug #1904.
+
+ * Thuban/UI/view.py (MapCanvas.OnPaint): Wrap code
+ with try/finally. Fixes RTBug #1904.
+ (MapCanvas.FitSelectedToWindow): If a single point is selected
+ simply center it on the display. Fixes RTBug #1849.
+
+ * extensions/thuban/gdalwarp.cpp: Removed code that allowed gdalwarp
+ to be compiled as a standalone app. Now the code can only be
+ called from Python which simplifies the parameter passing.
+ (ProjectRasterFile): Handle Python arguments. Remove code that
+ checks for a destination dataset. Add more clean up code.
+
+ * test/test_map.py (TestMapWithContents.test_raise_layer_top,
+ TestMapWithContents.test_lower_layer_bottom):
+ Test Map.MoveLayerToTop() and Map.MoveLayerToBottom() respectively.
+ Fixes RTBug #1907.
+
+ * Thuban/UI/mainwindow.py (MainWindow.ToggleLegend): Apply a full
+ extent to the map when the legend is toggled. Fixes RTBug #1881.
+
+2003-05-29 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/tableview.py (LayerTableFrame.OnClose): Bug-fix: Now
+ unsubscribes all that is subcribed in __init__.
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.DuplicateLayer)
+ (MainWindow.CanDuplicateLayer): New methods to implement the
+ Layer/Duplicate command.
+ (layer_duplicate command): New.
+ (main_menu): Add layer_duplicate to the Layer menu.
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tableview.py (NullRenderer.Draw): New. Our own
+ renderer so that NULL/None values get displayed differently (by a
+ gray rectangle).
+ (TableGrid.__init__): Override the default renderers
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.SetShapeStore): Set the
+ classification to "None" if the type of the field has changed.
+
+ * test/test_layer.py (SetShapeStoreTests): New. Class with a few
+ test for the Layer.SetShapeStore method
+
+2003-05-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.TreeInfo): Fixed a bug (a layer
+ does not necessarily have a filename).
+
+2003-05-28 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableClose, MainWindow.TableShow):
+ sort the selection list for the dialog.
+
+2003-05-28 Frank Koormann <frank.koormann at intevation.de>
+
+ * extensions/thuban/wxproj.cpp
+ (project_point): Removed cast to int for projected point coordinates.
+ (shape_centroid): Return last point if all polygon vertices fall
+ to one point.
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (_can_unjoin): Add doc-string and cope
+ with layers that don't have shapestores, i.e. raster layers.
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (DBFTable.__init__): Omit the extension
+ when determining the title from the filename.
+
+ * test/test_dbf_table.py (TestDBFTable.test_title): Update to
+ reflect changes in the way the title is derived from the filename
+
+2003-05-28 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableShow):
+ Added wxDEFAULT_DIALOG_STYLE to show table dialog styles.
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.delegated_messages): Also
+ delegate SelectedLayer.
+ (MainWindow.LayerUnjoinTable): Implement.
+ (_can_unjoin): New. Helper function for the sensitivity of the
+ layer/unjoin command.
+
+ * Thuban/Model/data.py (ShapefileStore.OrigShapeStore)
+ (DerivedShapeStore.OrigShapeStore): New. Return the original
+ shapestore. Used to figure out how to unjoin.
+ (DerivedShapeStore.Shapefile): Fix a typo.
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog): Extend to handle layer joins as
+ well
+ (JoinDialog.__init__): Use the layer parameter and only build the
+ left choice when a layer is given
+ (JoinDialog.OnJoin): Handle layer joins as well
+ (JoinDialog.OnLeftTable, JoinDialog.OnRightTable): Handle the case
+ that the user selects the "Select..." item. The sensitivitly
+ updating is now in update_sensitivity
+ (JoinDialog.y): New method to refactor the sensitivity update of
+ the join button into its own method.
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerJoinTable): Implement.
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (table_close command): Make it sensitive
+ iff there are unreferenced tables in the session
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/messages.py (TABLE_REMOVED): New message.
+
+ * Thuban/Model/session.py (Session.UnreferencedTables): New method
+ to return tables that are not referenced by other tables or shape
+ stores and can be removed.
+ (Session.RemoveTable): Issue a TABLE_REMOVED message after
+ removing the table
+
+ * Thuban/UI/mainwindow.py: Remove unused imports
+ (MainWindow.TableClose): Implement.
+
+ * Thuban/UI/tableview.py (TableFrame.__init__): Subscribe to some
+ messages so that the frame will be automatically closed when a new
+ session is opened or the table is removed.
+ (TableFrame.OnClose): Unsubscribe the Subscriptions made in
+ __init__
+ (TableFrame.close_on_session_replaced)
+ (TableFrame.close_on_table_removed): New. Subscribers that close
+ the window
+
+ * test/test_session.py (TestSessionMessages.test_remove_table)
+ (TestSessionSimple.test_remove_table): Move the test to
+ TestSessionSimple and add test for the TABLE_REMOVED message
+ (TestSessionBase.setUp): Also subscribe to TABLE_REMOVED
+ (TestSessionSimple.test_unreferenced_tables) New. Test for the
+ UnreferencedTables method.
+ (UnreferencedTablesTests): New. Class with some more sophisticated
+ tests for UnreferencedTables.
+
+2003-05-27 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/tableview.py (QueryTableFrame.__init__): The "_S_election"
+ display has some unwanted side effects. Removed again.
+
+2003-05-27 Frank Koormann <frank.koormann at intevation.de>
+
+ * Resources/Bitmaps/legend_icon_layer.xpm: New, icon for legend.
+
+ * Thuban/UI/legend.py (LegendTree.__FillTree): Use "legend_icon_layer"
+
+2003-05-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * test/test_menu.py (MenuTest.test): Added test for
+ Menu.RemoveItem().
+
+ * Thuban/UI/menu.py (Menu.RemoveItem): New. Remove an item from
+ the menu.
+
+2003-05-27 Frank Koormann <frank.koormann at intevation.de>
+
+ Nonmodal dialogs without parent (i.e. they can fall behind the main
+ window)
+
+ * Thuban/UI/mainwindow.py (MainWindow.OnClose): Explicitly destroy
+ all dialogs in the dialogs dictionary and the canvas.
+
+ * Thuban/UI/dialogs.py (NonModalNonParentDialog): New class, without
+ parent, i.e. can fall behind other windows.
+ (NonModalDialog.OnClose): Check is dialog is in mainwindow.dialog
+ dictionary before removing it.
+
+ * Thuban/UI/classifier.py: Dialog derived from NonModalNonParentDialog
+
+ * Thuban/UI/projdialog.py: Dialog derived from NonModalNonParentDialog
+ * Thuban/UI/tableview.py: Dialog derived from NonModalNonParentDialog
+ * Thuban/UI/tree.py: Dialog derived from NonModalNonParentDialog
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.ShowTableView): New. Open a
+ tableview dialog
+ (MainWindow.TableShow): Use ShowTableView to open the dialogs.
+ Also, don't use the table's titles as the dialog names. The titles
+ aren't guaranteed to be unique.
+ (MainWindow.TableOpen): Open a table view dialog after opening the
+ table
+
+2003-05-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Remove the Table/Hide menu item. Its
+ effect can be achieved by simply closing the window showing the
+ table.
+ (MainWindow.TableHide): Removed.
+ (main_menu): Removed "table_hide"
+
+2003-05-27 Frank Koormann <frank.koormann at intevation.de>
+
+ Fix legend tree display problems under Win32
+
+ * Thuban/UI/legend.py: BMP_SIZE_W = 15
+ (LegendTree.__FillTree): Display "legend_icon_map.xpm" with layer title.
+ (LegendTree.__FillTreeLayer): Explicitely set SelectedImage.
+
+ * Resources/Bitmaps/legend_icon_map.xpm: New icon for legend.
+
+2003-05-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/menu.py (Menu.InsertSeparator): Additional optional parameter
+ 'after' now allows to insert separators almost anywhere in the menu.
+
+2003-05-27 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/tableview.py (QueryTableFrame.__init__): Underline the
+ "S" of selection box label to hint on hot key (Alt-S). Works under
+ Win32 but is ignored under GTK.
+
+2003-05-26 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.__do_layout, ProjPanel._DoLayout):
+ Center Choices.
+
+2003-05-26 Bernhard Herzog <bh at intevation.de>
+
+ Remove the Precision methods again. They're too DBF specific to be
+ part of the table interface and they're only used in table_to_dbf
+ anyway.
+
+ * Thuban/Model/transientdb.py (TransientTableBase.Width):Use a
+ fixed precision of 12 for doubles.
+ (TransientTableBase.Precision): Removed
+ (AutoTransientTable.Width): Delegate to self.table.
+
+ * Thuban/Model/table.py (DBFTable.Precision)
+ (MemoryTable.Precision): Removed.
+ (MemoryTable.Width): Use a fixed precision of 12 for doubles.
+ (table_to_dbf): Use a fixed precision of 12 for floats unless the
+ column object specifies something else.
+
+ * test/test_dbf_table.py (TestTableToDBF.test_table_to_dbf): New.
+ test for table_to_dbf
+
+2003-05-26 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_transientdb.py
+ (TestTransientTable.run_iceland_political_tests): Fix a comment.
+
+2003-05-26 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableOpen): Real
+ implementation. Mark parts of the file format strings for
+ localization.
+
+ * Thuban/Model/session.py (Session.OpenTableFile): New. Open a dbf
+ file and add the table to the tables managed by the session
+
+ * test/test_session.py (TestSessionSimple.test_open_table_file):
+ New. test case for OpenTableFile
+
+2003-05-26 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/controls.py, Thuban/UI/identifyview.py, Thuban/UI/join.py,
+ Thuban/UI/labeldialog.py, Thuban/UI/mainwindow.py,
+ Thuban/UI/proj4dialog.py, Thuban/UI/tableview.py, Thuban/UI/view.py:
+ Replace the true/false of wxWindows by True/False of Python 2.2.1.
+
+2003-05-26 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/tableview.py (LayerTableFrame.__init__): If there is
+ already a selection present, update the grid accordingly.
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableShow): Make the dialog
+ resizeable and increase its initial size.
+
+2003-05-26 Frank Koormann <frank.koormann at intevation.de>
+
+ Table export functionality
+
+ * Thuban/Model/table.py (DBFTable.Width, MemoryTable.Width):
+ Return width (in characters) for a column.
+ (DBFTable.Precision, MemoryTable.Precision): Return decimal precision.
+ (table_to_dbf): Write table to dbf file.
+ (table_to_csv): Write table to csv file.
+
+ * Thuban/Model/transientdb.py (TransientTableBase.Width,
+ TransientTableBase.Precision): Return column width and precision.
+
+ * Thuban/UI/tableview.py (QueryTableFrame.OnSaveAs): Call table_to_dbf
+ or table_to_csv depending on file selection.
+
+ * test/test_dbf_table.py:
+ Test table_to_dbf (extension of former part of test).
+
+ * test/test_csv_table.py:
+ Test table_to_csv.
+
+2003-05-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.OnJoin): Use _() for strings.
+ Use QueryTableFrame instead of TableFrame.
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Prefix the
+ table window with 'Layer Table:' instead of 'Table:'.
+
+2003-05-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ Give all tables a title via mix-in TitledObject.LayerShowTable
+
+ * Thuban/Model/base.py (TitledObject.SetTitle): Call method 'issue'
+ only if it exists.
+
+ * Thuban/Model/table.py (DBFTable, MemoryTable): mix-in TitledObject
+ and call its init-method with a default title. Remove Title() method.
+
+ * Thuban/Model/transientdb.py (TransientTable, TransientJoinedTable,
+ AutoTransientTable): mix-in TitledObject and call its init-method with
+ a default title. Remove Title() method.
+
+2003-05-23 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.AddShapeStore): Define
+ AddShapeStore analogously to AddTable.
+
+ * test/test_session.py (TestSessionSimple.test_add_shapestore):
+ New. Test for AddShapeStore
+
+2003-05-23 Jan-Oliver Wagner <jan at intevation.de>
+
+ Introducing QueryTableFrame and a very coarse ShowTable implementation.
+
+ * Thuban/UI/tableview.py (LayerTableFrame, QueryTableFrame): Split the
+ class LayerTableFrame into two classes, LayerTableFrame and QueryTableFrame.
+ The latter implements the selection GUI without dependency on a layer.
+ LayerTableFrame now is derived from QueryTableFrame and connects
+ to a layer.
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableShow): A very coarse
+ implementation that still needs work.
+
+ * Thuban/Model/layer.py (Layer.TreeInfo): Added filename.
+
+2003-05-22 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.__init__):
+ Added "outer_join = False" as optional parameter.
+ (TransientJoinedTable.create): If outer join is true, perform a
+ "LEFT OUTER JOIN" instead of "JOIN", which preserves all records of
+ the left table. Records not matching are filled with 0 / None.
+
+ * Thuban/UI/join.py (JoinDialog.__init__): Checkbox for outer join.
+ (JoinDialog.OnJoin): Consider outer join check box.
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.OnJoin): Use exc_info in a
+ somewhat safer way. Storing the traceback in a local variable can
+ lead to memory leaks
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.OnJoin): Make sure to really call
+ the wxMessageDialog's Destroy() method.
+
+2003-05-22 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/join.py (JoinDialog.__init__): Make use of
+ TransientTable.Title()
+
+2003-05-22 Frank Koormann <frank.koormann at intevation.de>
+
+ Join Dialog, initial version.
+
+ * Thuban/UI/mainwindow.py (MainWindow.TableJoin): Removed print.
+
+ * Thuban/UI/join.py (JoinDialog): Functional implementation of
+ former framework. Renamed Table1/Table2 to LeftTable/RightTable
+ in all occurences.
+
+ * Thuban/Model/transientdb.py (TransientJoinedTable.__doc__):
+ Typo fixed.
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ Give the tables titles so that the GUI can display more meaningful
+ names. For now the titles are fixed but depend on e.g. filenames
+ or the titles of the joined tables.
+
+ * Thuban/Model/transientdb.py (TransientTable.Title)
+ (TransientJoinedTable.Title, AutoTransientTable.Title): New.
+
+ * Thuban/Model/table.py (DBFTable.Title, MemoryTable.Title): New.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_auto_transient_table_title): New. Test
+ for the Title method
+ (TestTransientTable.test_transient_joined_table)
+ (TestTransientTable.test_transient_table): Add test for the Title
+ methods
+
+ * test/test_memory_table.py (TestMemoryTable.test_title): New.
+ Test for the Title method
+
+ * test/test_dbf_table.py (TestDBFTable.test_title): New. Test for
+ the Title method
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_layer.py (TestLayer.setUp, TestLayer.tearDown):
+ Provide a better way to destroy the layers
+ (TestLayer.test_base_layer, TestLayer.test_arc_layer)
+ (TestLayer.test_point_layer, TestLayer.test_empty_layer)
+ (TestLayer.test_polygon_layer, TestLayer.test_get_field_type): Use
+ the new way to destroy the layers.
+ (TestLayer.test_derived_store): New. Test for using a layer with a
+ DerivedShapeStore
+
+ * Thuban/Model/layer.py (Layer.SetShapeStore): Only set the
+ filename if the shape store actually has one.
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (DBFTable.FileName): New. Accessor method
+ for the filename
+
+ * test/test_dbf_table.py (TestDBFTable.test_filename): New. Test
+ for the FileName method
+ (TestDBFTableWriting.test_write): Fix spelling of filename
+
+2003-05-22 Thomas Koester <tkoester at intevation.de>
+
+ * Thuban/Model/range.py, test/test_range.py: Brought over new Range
+ from SciParam that now really is immutable.
+
+2003-05-22 Frank Koormann <frank.koormann at intevation.de>
+
+ Layer Top/Bottom placement added to legend.
+
+ * Thuban/UI/legend.py
+ (LegendPanel._OnMoveTop(), LayerPanel._OnMoveBottom): New, methods
+ bound to tool events.
+ (LegendTree.MoveCurrentItemTop(), LegendTree.MoveCurrentItemBottom):
+ New, methods binding the event methods with the map methods.
+
+ * Thuban/Model/map.py (Map.TopLayer(), Map.BottomLayer()): New, place
+ layer at top/bottom of layer stack.
+
+ * Resources/Bitmaps/top_layer.xpm: New button icon.
+
+ * Resources/Bitmaps/bottom_layer.xpm: New button icon.
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.RemoveTable): New method to
+ remove tables
+
+ * test/test_session.py (TestSessionSimple.test_remove_table): New.
+ Test for RemoveTable
+
+2003-05-22 Thomas Koester <tkoester at intevation.de>
+
+ * Thuban/Model/classgen.py: Added short module doc string and CVS id.
+ (ClassGenerator.GenUniformDistribution): Use new Range __init__, too.
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ Implement a way to discover dependencies between tables and
+ shapestores.
+
+ * Thuban/Model/transientdb.py (TransientTableBase.Dependencies)
+ (TransientJoinedTable.Dependencies)
+ (AutoTransientTable.SimpleQuery): New. Implement the dependencies
+ interface
+ (TransientJoinedTable.__init__): Keep tack of the original table
+ objects in addition to the corresponding transient tables.
+
+ * Thuban/Model/table.py (DBFTable.Dependencies)
+ (MemoryTable.Dependencies): New. Implement the dependencies
+ interface
+
+ * Thuban/Model/data.py (ShapeTable): New. Helper class for
+ ShapefileStore
+ (ShapefileStore.__init__): Use ShapeTable instead of
+ AutoTransientTable
+ (ShapefileStore.Table, ShapefileStore.Shapefile): Add doc-strings
+ (ShapefileStore.FileName, ShapefileStore.FileType): New. Accessor
+ methods for filename and type
+ (ShapefileStore.Dependencies): New. Implement the dependencies
+ interface
+ (DerivedShapeStore): New class to replace SimpleStore. The main
+ difference to SimpleStore is that it depends not on a shapefile
+ but another shapestore which expresses the dependencies a bit
+ better
+ (SimpleStore.__init__): Add deprecation warning.
+
+ * test/test_dbf_table.py (TestDBFTable.test_dependencies): New.
+ Test for the Dependencies method.
+
+ * test/test_memory_table.py (TestMemoryTable.test_dependencies):
+ New. Test for the Dependencies method.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_auto_transient_table_dependencies): New.
+ Test for the Dependencies method.
+ (TestTransientTable.test_transient_joined_table): Add test for the
+ Dependencies method.
+
+ * test/test_session.py (TestSessionSimple.setUp)
+ (TestSessionSimple.tearDown): New. Implement a better way to
+ destroy the sessions.
+ (TestSessionSimple.test_initial_state)
+ (TestSessionSimple.test_add_table): Bind session to self.session
+ so that it's destroyed by tearDown
+ (TestSessionSimple.test_open_shapefile): New. Test for
+ OpenShapefile and the object it returns
+
+2003-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.AddTable): New method to
+ register tables with the session.
+ (Session.Tables): Return the tables registered with AddTable too.
+
+ * test/test_session.py (TestSessionSimple.test_add_table): New.
+ Test case for the AddTable method
+
+2003-05-22 Frank Koormann <frank.koormann at intevation.de>
+
+ UI polishing updates: Place main buttons (OK, Cancel, etc) in the
+ lower right corner, center labels for selections, initialize controls
+ in reasonable order for keyboard navigation.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__, ProjFrame.__doLayout)
+ (ProjFrame.__DoOnProjAvail): Determine position of current projection
+ using the wxListBox.FindString() method. Still a problem (#1886)
+
+ * Thuban/UI/classifier.py
+ (Classifier.__init__, SelectPropertiesDialog.__init__)
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__,
+ (ClassGenDialog.__DoOnGenTypeSelect): Moved initialization of the
+ different classification types from here to __init__.
+ (GenUniquePanel.__init__): Set the column width of the first field
+ in the Field ListCtrl to the full width.
+
+ * Thuban/UI/tableview.py (LayerTableFrame.__init__): Rename 'Save As'
+ Button to 'Export'. Center Buttons in Selection Box, set Focus to
+ Grid.
+ (LayerTableFrame.OnKeyDown()): New, bound to the grid with EVT_KEY_DOWN,
+ changes focus to the Selection when pressing "Alt-S".
+
+ * Thuban/UI/legend.py (LegendTree.__SetVisibilityStyle): Only gray out
+ the text if not visible. The italic font sometimes exceeds the
+ rendering area.
+
+2003-05-21 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/dock.py (DockFrame): Rename references to _OnClose
+ to OnClose so that Thuban closes correctly.
+
+ * Thuban/UI/mainwindow.py (MainWindow.OnClose): Call
+ DockFrame.OnClose, not DockFrame._OnClose.
+
+2003-05-21 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py (ClassGenerator.GenQuantiles): Remove
+ references to 'inf' and use new Range __init__ to pass floats
+ directly rather than converting them to strings first.
+ Fixes RTBug #1876.
+
+ * Thuban/Model/classification.py (ClassGroupRange.SetRange):
+ Use new Range ___init__ to pass floats.
+
+ * Thuban/Model/layer.py (RasterLayer.__init__): Test if the
+ filename is a valid image file. Throw IOError otherwise.
+
+ * Thuban/Model/range.py: Brought over new Range from SciParam that
+ is immutable and has an __init__ which can accept floats.
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddLayer): Move OpenShapefile
+ into try block. AddLayer doesn't throw any exceptions anymore.
+ (MainWindow.AddRasterLayer): Move constructor of RasterLayer into
+ try block.
+
+ * Thuban/UI/projdialog.py (GeoPanel.__init__): Put Degrees as
+ the first item in choices. Fixes RTBug #1882.
+
+ * Thuban/UI/renderer.py (MapRenderer.render_map): Check if scale
+ has gone to 0 which is a serious problem. abort.
+ (MapRenderer.draw_raster_layer): Catch IOError seperately and
+ print the error from GDAL.
+
+ * Thuban/UI/tableview.py (TableGrid.__init__): Call
+ ToggleEventListeners to turn on listening.
+ (TableGrid.ToggleEventListeners): New. Turns event listening on
+ and off so as to prevent excessive messages.
+ (LayerTableFrame.OnQuery): Use TableGrid.ToggleEventListeners
+ to suppress excessive messages when selecting many rows.
+ Fixes RTBug #1880.
+
+ * Thuban/UI/view.py: Added checks against if scale == 0. This
+ is a serious problem that can occur when an image without
+ geo data is loading and causes the map projection bounds to
+ go to infinity. Right now, the solution is to simply try
+ to recover.
+
+ * extensions/thuban/cpl_mfile.cpp (MFILEClose): Make sure
+ to set the MFILEReceiver attributes even if the data is NULL.
+
+ * extensions/thuban/gdalwarp.cpp: Improved the error handling
+ and passed GDAL messages back up to the Python layer. Also
+ tried to fix some memory leaks that were present in the original
+ utility but didn't matter because the program aborted.
+
+ * test/test_range.py: Copied over tests from SciParam. Removed
+ tests against importing. Fixes RTBug #1867.
+
+2003-05-21 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_load.py: Remove unused imports and restructure the
+ test code
+ (LoadSessionTest): Split into one class for each test and turn
+ LoadSessionTest itself into the base class for all such session
+ tests.
+ (ClassificationTest): New base class for load tests that test
+ classifications
+ (TestSingleLayer, TestLayerVisibility, TestClassification)
+ (TestLabels, TestLayerProjection, TestRasterLayer): New classes
+ for the individual tests
+
+ * test/support.py (FileLoadTestCase.filename): New base class for
+ file loading tests
+
+2003-05-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Resources/Projections/defaults.proj: Renamed 'Universal Transverse
+ Mercator' to 'UTM Zone 32' as a more convenient example.
+ Added 'Gauss Krueger Zone 6'.
+
+ * Data/iceland_sample_raster.thuban: political polygon now
+ filled transparent to have the raster image visible at once.
+
+2003-05-21 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow): Renamed _OnClose() back to
+ OnClose() to keep in sync with extensions. Internally Thuban
+ still uses "underscored" names.
+
+2003-05-20 Jonathan Coles <jonathan at intevation.de>
+
+ This puts back Raster layer support. These layers support projections
+ through the GDAL library. Currently, the CVS version is being used.
+ There are no Debian packages available although this may change soon.
+ A GDAL driver was extended to support writing to memory rather to
+ files.
+
+ There is still some work that needs to be done, such as some error
+ handling when loading invalid images or when there is a problem
+ projecting the image. This putback simply checks in the majority
+ of the work.
+
+ * setup.py: Add gdalwarp library extension.
+
+ * Thuban/Model/layer.py (BaseLayer.HasClassification): New.
+ Defaults to False, but can be overridden by subclasses if they
+ support classification.
+ (RasterLayer): New. Defines a new layer that represents an
+ image.
+
+ * Thuban/Model/load.py (SessionLoader.__init__): Add rasterlayer
+ tag handler.
+ (SessionLoader.start_layer): Encode the filename.
+ (SessionLoader.start_rasterlayer, SessionLoader.end_rasterlayer):
+ New. Supports reading a rasterlayer tag.
+
+ * Thuban/Model/map.py (Map.BoundingBox): Fix typo in comment.
+
+ * Thuban/Model/save.py (XMLWriter.encode): Don't assume that we
+ get a string in Latin1. If we get such as string convert it to
+ unicode first, otherwise leave if alone before encoding.
+ (SessionSaver.write_layer): Add support for writing both Layers
+ and RasterLayers.
+
+ * Thuban/Model/transientdb.py (AutoTransientTable.SimpleQuery):
+ The right argument may not be a string, it could also be a Column.
+
+ * Thuban/UI/application.py (ThubanApplication.CreateMainWindow):
+ Make initial window size 600x400. Fixes RTBug #1872.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Rearrange how
+ the dialog is constructed so that we can support layers that
+ do not have classifications.
+ (Classifier._OnTry): Only build a classification if the layer
+ supports one.
+
+ * Thuban/UI/legend.py: Change all checks that a layer is an
+ instance of Layer into checks against BaseLayer.
+ (LegendTree.__FillTreeLayer): Only add children to a branch if
+ the layer supports classification.
+
+ * Thuban/UI/mainwindow.py (MainWindow.NewSession,
+ MainWindow.OpenSession): Don't proceed with an action if the
+ user chooses Cancel when they are asked to save changes.
+ (MainWindow.AddRasterLayer): New. Open a dialog to allow the
+ user to select an image file. Create a new RasterLayer and add
+ it to the map.
+
+ * Thuban/UI/renderer.py (MapRenderer.render_map): Add support
+ for rendering RasterLayer layers.
+ (MapRenderer.draw_raster_layer): Actually method that calls
+ the GDALWarp python wrapper and constructs an image from the
+ data returned.
+
+ * Thuban/UI/tableview.py (LayerTableFrame.__init__): Change the
+ Choices symbols to match those used in the table query method.
+ Replace deprecated method calls on table with new method names.
+
+ * Thuban/UI/view.py (MapCanvas.set_view_transform): Try to limit
+ how small the scale can get. This still needs more testing.
+
+ * extensions/thuban/bmpdataset.cpp: New, but copied from GDAL.
+ Provides a driver to output in .bmp format.
+
+ * extensions/thuban/cpl_mfile.cpp, extensions/thuban/cpl_mfile.h:
+ New. Provides IO routines which write to memory, rather than a file.
+
+ * extensions/thuban/gdalwarp.cpp: New, but basically a direct copy
+ of the gdalwarp utility provided in GDAL. Added function calls
+ that can be accessed from python.
+
+ * Data/iceland_sample_raster.thuban: New. Sample file that uses
+ a raster layer.
+
+ * Data/iceland/island.tfw, Data/iceland/island.tif: New. Raster
+ layer image data.
+
+ * Doc/thuban.dtd: Added rasterlayer attribute definition.
+
+ * test/test_layer.py, test/test_load.py, test/test_save.py: Added
+ tests associated with the raster layer code.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_auto_transient_table_query): Added a test
+ for using a Column object as the "right" parameter to a query.
+
+2003-05-19 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/version.py (get_changelog_date):
+ Catch exceptions if ChangeLog does not exist.
+
+ * Thuban/UI/view.py (MapCanvas.Export): Bugfix
+
+2003-05-19 Frank Koormann <frank.koormann at intevation.de>
+
+ Extended version information for Thuban
+
+ * Thuban/version.py: New, version information for Thuban: Last
+ modification date and last ChangeLog entry date.
+
+ * Thuban/UI/mainwindow.py (MainWindow.About()): Extended version
+ information: Display Thuban, wxPython and Python version.
+
+2003-05-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/save.py: Remove some unused imports including the
+ __future__ import for nested_scopes as Thuban relies on Python 2.2
+ now.
+ (XMLWriter.encode): Remove the special case for a None argument.
+ In the saver encode is always called with a string argument.
+
+2003-05-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/__init__.py: Remove the work-around for the locale bug
+ in wxPython (at least when usinvg wxGTK) prior to 2.4. The symptom
+ of the bug was that e.g. float("1.2") would fail. Thuban now
+ requires 2.4.x.
+
+2003-05-16 Frank Koormann <frank.koormann at intevation.de>
+
+ Printing enhancement and WMF export (under Win32)
+
+ * Thuban/UI/renderer.py (ExportRenderer): New, derived from
+ ScreenRenderer. Renders Map, Legend and Scalebar for export.
+ (PrinterRenderer): New, derived from ExportRenderer. Replaces the old
+ PrintRender.
+
+ * Thuban/UI/view.py (MapPrintout.__init__): Enhanced parameter set
+ to fullfil information needed for PrinterRenderer.
+ (MapCanvas.Export): New. Export Map (currently only to WMF on Win32).
+ (MapCanvas.Print): Adapted to new MapPrintout.
+ (OutputTransform): General calculations to transform from canvas
+ coordinates to export/printing devices.
+
+ * Thuban/UI/mainwindow.py (MainWindow.ExportMap()): New. Added also
+ new method_command to call ExportMap, with platform dependency (only
+ __WXMSW__)
+
+ * Thuban/UI/scalebar.py (ScaleBar.DrawScaleBar): Position and Size
+ of scalebar drawing area as new parameters.
+
+ * Thuban/Model/scalebar.py (roundInterval): round long instead of int
+
+ * Thuban/UI/legend.py (ScalebarBitmap.__SetScale):
+ Update to extended scalebar.DrawScalebar header.
+
+ * test/test_export.py: New, test Thuban.UI.view.OutputTransform()
+
+ * test/test_scalebar.py: Made test executable as standalone.
+
+2003-05-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (Table): Remove this compatibility alias
+ for DBFTable.
+
+ * test/test_table.py: Import DBFTable as Table because that alias
+ doesn't exist anymore.
+
+ * Thuban/UI/classgen.py: Remove some unused imports
+
+2003-05-14 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classgen.py (ClassGenerator.GenSingletonsFromList):
+ Fix docstring.
+ (ClassGenerator.GenUniformDistribution): Fix spelling of method name.
+ (ClassGenerator.GenQuantiles): Use the left/right brackets and min/max
+ values of the supplied range to determine the beginning and end
+ bounds of the generated classes.
+
+ * Thuban/Model/range.py (Range.number_re): Now accepts floats that
+ do not have a leading 0 (.5 is now accepted as well as 0.5).
+
+ * Thuban/UI/classgen.py (ClassGenDialog.OnOK): Fix name of method
+ call to ClassGenerator.GenUniformDistribution.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__do_layout): Fix Windows
+ layout bug with the 'Projection' label.
+
+ * test/support.py (FloatTestCase): New. Needed for the Range tests.
+
+ * test/test_range.py: New. Imported from SciParam.
+
+2003-05-12 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classgen.py (GenQuantilesPanel.GetList): Replace call
+ to table.UniqueValues() with calls that retrieve all the values
+ from the table. This will need to be replaced by a method on table
+ which can simply return the list (perhaps more efficiently).
+
+2003-05-12 Jonathan Coles <jonathan at intevation.de>
+
+ The return value of ClassGenerator.CalculateQuantiles has changed.
+ Refer to the documentation for details.
+
+ * test/test_classgen.py: Modified Quantile tests to use the
+ new return values.
+
+ * Thuban/Model/classgen.py
+ (ClassGenerator.GenQuantiles): Add comments describing the parameters,
+ use new return values from CalculateQuantiles to produce the correct
+ range bounds in the Classification.
+ (ClassGenerator.CalculateQuantiles): Add more comments describing
+ the return values and parameters. Make minor adjustments to improve
+ the legibility of the code. Fix problem with adjusted not being set
+ in most cases.
+
+2003-05-12 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/Model/save.py (XMLWriter.encode()): Explicite call to unicode
+ and latin1. Fixes #1851 finally.
+
+2003-05-09 Jonathan Coles <jonathan at intevation.de>
+
+ * test/test_classgen.py: New. Tests the Quantile algorithm.
+
+ * Thuban/Model/classgen.py (ClassGenerator.CalculateQuantiles):
+ Clean up debugging statement, add comments, fix a small bug in the
+ returned adjusted percentiles.
+
+2003-05-09 Jonathan Coles <jonathan at intevation.de>
+
+ Introduces Range class from SciParam into the ClassGroupRange class,
+ and such ranges can now be saved and loaded from disk.
+
+ Quantiles are now available in the Classification Generator.
+
+ Initial support for building Queries on a table. Doesn't do anything
+ but run some tests.
+
+ * Thuban/Model/classification.py: Explicit imports.
+ (ClassGroupRange): Use the Range class to store the underlying
+ range information. The interface remains the same, except for
+ GetRange(), and you can also supply a Range object as the min
+ parameter to SetRange or __init__.
+
+ * Thuban/Model/load.py (XMLReader.encode): New. Encodes the given
+ string appropriately for use in Thuban. Fixes RTbug #1851.
+ (SessionLoader.end_projection): Handle the context of the
+ projection tag a bit better by looking at what objects are not
+ None. There was an assumption that a projection tag for a map
+ could occur before any layers.
+ (SessionLoader.start_clrange): Provide backward compatibility for
+ reading min/max values as well as the new range parameter.
+
+ * Thuban/Model/map.py: Explicit imports.
+
+ * Thuban/Model/resource.py: Import _.
+ (ProjFileSaver.write): write header using projfile.dtd.
+
+ * Thuban/Model/save.py: Explicit imports.
+ (XMLWriter.encode): New. Encode the given string from a format
+ used by Thuban into UTF-8. Fixes RTbug #1851.
+
+ * Thuban/UI/classgen.py: Explicit imports.
+ (ClassGenDialog.__init__): Clean up the code and add support
+ for Quantiles.
+ (ClassGenDialog.OnOK): Add support for Quantiles.
+ (GenQuantilesPanel): New. Input panel for Quantiles.
+ (ClassGenerator, CustomRamp, MonochromaticRamp, GreyRamp, RedRamp,
+ GreenRamp, BlueRamp, HotToColdRamp): Move to Thuban/Model/classgen.py
+
+ * Thuban/Model/classgen.py: New. Contains all the classes named above.
+
+ * Thuban/UI/classifier.py: Explicit imports.
+ (ClassTable.GetValueAsCust, ClassTable.__ParseInput,
+ ClassTable.SetValueAsCustom): Reworked to use new Range class.
+
+ * Thuban/UI/legend.py: Explicit imports.
+
+ * Thuban/UI/mainwindow.py: Add support for the Join Dialog. Added
+ a Table menu and associated method calls.
+ (MainWindow.choose_color): Removed. No longer needed.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__VerifyButtons): Save button
+ should be disabled if no projection is selected in the available
+ list.
+
+ * Thuban/UI/renderer.py: Explicit imports.
+
+ * Thuban/UI/tableview.py (TableGrid.OnRangeSelect): Fix some issues
+ with correctly selecting the rows and issuing the right events.
+ Be sure to call Skip() to allow the grid to do some of its own
+ handling which allows the rows to actually be selected.
+ (LayerTableGrid.select_shapes): Rename from select_shape. Supports
+ selecting multiple shapes.
+ (LayerTableFrame): Support for building Queries.
+ (LayerTableFrame.select_shapes): Allow multiple shapes to be selected.
+
+ * Thuban/UI/tree.py: Explicit imports.
+
+ * Thuban/UI/view.py (MapCanvas): Delegate "SelectedShapes" so the
+ table view can call it.
+
+ * test/test_classification.py: Explicit imports.
+ (TestClassification.test_ClassGroupRange): Fix test for new
+ Range class.
+
+ * Doc/thuban.dtd: Add range parameter for clrange.
+
+ * Thuban/Model/range.py: Taken from SciParam. Used as the underlying
+ object in ClassGroupRange, and also uesd for inputting ranges in
+ the classifer table and elsewhere.
+
+ * Thuban/UI/join.py: New. Initial Join dialog. No real functionality
+ yet.
+
+2003-05-09 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/scalebar.py (DrawScaleBar): Draw only if interval > 0.0.
+
+2003-05-08 Frank Koormann <frank.koormann at intevation.de>
+
+ Coding style updates
+
+ * test/test_scalebar.py: Replaced tab indentation by spaces.
+
+ * Thuban/UI/scalebar.py: Explicit imports.
+
+2003-05-08 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/scalebar.py
+ (ScaleBar.DrawScalebar): Format string bug fixed.
+
+2003-05-08 Frank Koormann <frank.koormann at intevation.de>
+
+ Reorganization of scalebar component (no wx in Thuban/Model)
+
+ * Thuban/Model/scalebar.py: Rendering moved to Thuban/UI/scalebar.py
+ (deriveInterval):
+ Calculate scalebar interval and unit which fits in width for scale.
+ (roundInterval): Round float.
+
+ * Thuban/UI/scalebar.py (ScaleBar): Scalebar rendering
+
+ * test/test_scalebar.py: Test for Thuban/Model/scalebar.py methods.
+
+ * Thuban/UI/legend.py: Import Thuban.UI.scalebar
+
+2003-05-08 Frank Koormann <frank.koormann at intevation.de>
+
+ * Thuban/UI/legend.py (ScalebarBitmap.SetCanvas):
+ Initialize ScaleBar with canvas.map
+
+ * Thuban/Model/scalebar.py (ScaleBar.roundInterval()): New,
+ round intervals to display smarter lengths
+ (ScaleBar.DrawScalebar): Draw Scalebar only if the map contains a
+ layer. If the maps has no projection applied grey the scalebar.
+
+2003-05-07 Frank Koormann <frank.koormann at intevation.de>
+
+ Basic Scalebar features added.
+
+ * Thuban/Model/scalebar.py (ScaleBar): New, scalebar rendering.
+
+ * Thuban/UI/legend.py (LegendPanel): Added scalebar bitmap
+ (ScaleBarBitmap): New, links the scalebar bitmap with view messages
+ and the renderer.
+
+ * Thuban/UI/view.py (MapCanvas.set_view_transform): Issue SCALE_CHANGED.
+
+ * Thuban/UI/messages.py: SCALE_CHANGED added.
+
+2003-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.__init__): New instance
+ variable shapestores to hold a list of all open shapestore objects
+ (Session.ShapeStores): New. Accessor method for the shapestores
+ list.
+ (Session._add_shapestore, Session._clean_weak_store_refs): New.
+ Internal methods to maintain the shapestores list.
+ (Session.Tables): New. Return all tables open in the session.
+ (Session.OpenShapefile): Insert the new ShapeStore into the
+ shapestores list.
+
+ * test/test_session.py (TestSessionSimple.test_initial_state): Add
+ tests for ShapeStores and Tables
+ (TestSessionWithContent.test_shape_stores)
+ (TestSessionWithContent.test_tables): New. Test cases for
+ ShapeStores and Tables
+
+2003-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientTableBase.ReadRowAsDict):
+ Add comments about the optimizations used.
+ (AutoTransientTable.ReadValue, TransientTableBase.ReadValue): New.
+ Implement the ReadValue table interface method.
+
+ * test/test_transientdb.py
+ (TestTransientTable.run_iceland_political_tests)
+ (TestTransientTable.test_transient_joined_table): Add tests for
+ ReadValue
+
+2003-05-07 Frank Koormann <frank.koormann at intevation.de>
+
+ * Resources/Bitmaps/fulllayerextent.xpm,
+ Resources/Bitmaps/fullselextent.xpm: Replaced the place holders with
+ new icons.
+
+2003-05-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (AutoTransientTable.SimpleQuery):
+ New. Simply delegate to the transient table's version.
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_auto_transient_table_query): New. Test
+ case for AutoTransientTable's SimpleQuery
+
+2003-05-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientTableBase.SimpleQuery):
+ Implement a simple query method for the query dialog
+ (TransientTableBase.create): Add an INTEGER PRIMARY KEY that holds
+ the row index or shapeid.
+ (TransientTable.create): Insert the right value of the row index
+ (TransientJoinedTable.create): Copy the row index of the left
+ table to the joined result table
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transient_table_read_twice): Fix
+ doc-string
+ (TestTransientTable.test_transient_table_query): New. Test for the
+ SimpleQuery method
+
+2003-05-06 Bernhard Herzog <bh at intevation.de>
+
+ Convert all table users to use the new table interface. This only
+ covers Thuban itself, not GREAT-ER or other applications built on
+ Thuban yet, so the compatibility interface stays in place for the
+ time being but it now issues DeprecationWarnings.
+
+ Finally, the new Table interface has a new method, HasColumn.
+
+ * Thuban/Model/table.py (OldTableInterfaceMixin): All methods
+ issue deprecation warnings when they're. The warnings refer to the
+ caller of the method.
+ (OldTableInterfaceMixin.__deprecation_warning): New. Helper method
+ for the deprecation warnings
+
+ * test/test_table.py: Ignore the deprecation warnings for the old
+ table in the tests in this module. The purpose of the tests is to
+ test the old interface, after all.
+
+ * test/test_transientdb.py
+ (TestTransientTable.run_iceland_political_tests): Use the
+ constants for the types. Add a test for HasColumn
+ (TestTransientTable.test_transient_joined_table): Adapt to new
+ table interface. Add a test for HasColumn
+ (TestTransientTable.test_transient_table_read_twice): Adapt to new
+ table interface
+
+ * Thuban/UI/tableview.py (DataTable.SetTable, DataTable.GetValue):
+ Adapt to new table interface
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Adapt to
+ new table interface
+
+ * Thuban/UI/controls.py (RecordListCtrl.fill_list)
+ (RecordTable.SetTable): Adapt to new table interface
+
+ * Thuban/UI/classifier.py (Classifier.__init__)
+ (Classifier.__init__): Adapt to new table interface
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__)
+ (GenUniformPanel._OnRetrieve, GenUniquePanel._OnRetrieve): Adapt
+ to new table interface
+
+ * Thuban/Model/transientdb.py (TransientTableBase.HasColumn)
+ (AutoTransientTable.HasColumn): Implement the new table interface
+ method
+ (AutoTransientTable.ReadRowAsDict, AutoTransientTable.ValueRange)
+ (AutoTransientTable.UniqueValues): Adapt to new table interface
+
+ * Thuban/Model/layer.py (Layer.SetShapeStore, Layer.GetFieldType):
+ Adapt to new table interface
+
+ * test/test_layer.py (TestLayer.open_shapefile): Helper method to
+ simplify opening shapefiles a bit easier.
+ (TestLayer.test_arc_layer, TestLayer.test_polygon_layer)
+ (TestLayer.test_point_layer): Use the new helper method
+ (TestLayer.test_get_field_type): New. Test for the GetFieldType
+ method
+
+ * test/test_dbf_table.py (TestDBFTable.test_has_column): Test for
+ the new table method
+
+ * test/test_memory_table.py (TestMemoryTable.test_has_column):
+ Test for the new table method HasColumn
+
+2003-05-06 Jonathan Coles <jonathan at intevation.de>
+
+ Addresses the "Selection Extent" wish of RTbug #1787.
+
+ * Resources/Bitmaps/fulllayerextent.xpm,
+ Resources/Bitmaps/fullselextent.xpm: Bitmaps for layer and selection
+ extent. These are just place holders for the real bitmaps.
+
+ * Thuban/Model/layer.py (Shape): Since a Shape is immutable only
+ calculate the bounding box once (the first time compute_bbox() is
+ called).
+ (Layer.ShapesBoundingBox): New. Given a list of shape ids, return
+ the bounding box for the shapes in lat/long coordinates.
+
+ * Thuban/UI/mainwindow.py: Added new "Full selection extent" menu
+ option.
+ (MainWindow.has_selected_shapes): New. Returns true if there are
+ any selected shapes.
+ (MainWindow.FullSelectionExtent): New. Calls
+ MapCanvas.FitSelectedToWindow() when the user selects the menu option.
+ (_has_selected_shapes): New. Returns true if there are any
+ selected shapes.
+
+ * Thuban/UI/selection.py (Selection.HasSelectedShapes): New. Returns
+ true if there are any selected shapes.
+
+ * Thuban/UI/view.py (MapCanvas): Added delegated method
+ HasSelectedShapes.
+ (MapCanvas.FitSelectedToWindow): New. Centers and scales any selected
+ shapes on the canvas using the map projection (if any).
+
+ * test/test_layer.py (TestLayer.test_arc_layer): Add some tests
+ for Layer.ShapesBoundingBox().
+
+2003-05-06 Bernhard Herzog <bh at intevation.de>
+
+ * Resources/Projections/defaults.proj: Fix spelling of Mercator
+
+2003-05-05 Jonathan Coles <jonathan at intevation.de>
+
+ Addresses the "Full Layer Extent" wish of RTbug #1787.
+
+ * Resources/Projections/defaults.proj: Added UK National Grid.
+
+ * Thuban/UI/mainwindow.py: Added new "Full layer extent" menu option.
+ (MainWindow.FullLayerExtent): New. Calls MapCanvas.FitLayerToWindow()
+ when the user selects the menu option.
+
+ * Thuban/UI/view.py (MapCanvas.FitLayerToWindow): New. Centers and
+ scales the given layer on the canvas using the map projection.
+
+2003-05-05 Bernhard Herzog <bh at intevation.de>
+
+ Convert the table implementations to a new table interface. All
+ tables use a common mixin class to provide backwards compatibility
+ until all table users have been updated.
+
+ * Thuban/Model/table.py (OldTableInterfaceMixin): Mixin class to
+ provide backwards compatibility for table classes implementing the
+ new interface
+ (DBFTable, MemoryTable): Implement the new table interface. Use
+ OldTableInterfaceMixin as base for compatibility
+ (DBFColumn, MemoryColumn): New. Column description for DBFTable
+ and MemoryTable resp.
+
+ * test/test_dbf_table.py: New. Test cases for the DBFTable with
+ the new table interface.
+
+ * test/test_memory_table.py: New. Test cases for the MemoryTable
+ with the new table interface.
+
+ * test/test_table.py: Document the all tests in this file as only
+ for backwards compatibility. The equivalent tests for the new
+ interface are in test_memory_table.py and test_dbf_table.py
+ (MemoryTableTest.test_read): field_info should be returning tuples
+ with four items
+ (MemoryTableTest.test_write): Make doc-string a more precise.
+
+ * Thuban/Model/transientdb.py (TransientTableBase): Convert to new
+ table interface. Derive from from OldTableInterfaceMixin for
+ compatibility.
+ (TransientTableBase.create): New intance variable column_map to
+ map from names and indices to column objects
+ (TransientTable.create): Use the new table interface of the input
+ table
+ (AutoTransientTable): Convert to new table interface. Derive from
+ from OldTableInterfaceMixin for compatibility.
+ (AutoTransientTable.write_record): Removed. It's not implemented
+ yet and we still have to decide how to handle writing with the new
+ table and data framework.
+
+ * test/test_transientdb.py
+ (TestTransientTable.run_iceland_political_tests)
+ (TestTransientTable.test_transient_joined_table): Use the new
+ table interface
+
+2003-05-05 Jonathan Coles <jonathan at intevation.de>
+
+ This is namely a collection of UI updates to improve user interactivity.
+ Tabbing between controls now exists and you can use ESC to close dialog
+ boxes; ENTER will active the default button.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__): Rearrange the
+ order that the controls are created so that tabbing works correctly.
+ (ClassGenDialog.OnOK): Renamed from _OnGenerate() so that the
+ wxDialog can handle the default button correctly.
+ (ClassGenDialog.OnCancel): Renamed from _OnCloseBtn() for the
+ same reasons as for OnOK.
+ (GenUniformPanel._OnRetrieve): Call wxBeginBusyCursor/wxEndBusyCursor
+ when we ask the table for the maximum/minimum values of a field
+ which could take a very long time.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Rearrange the
+ order that the controls are created so that tabbing works correctly.
+ (SelectPropertiesDialog.__init__): Rearrange the order that the
+ controls are created so that tabbing works correctly.
+
+ * Thuban/UI/dialogs.py: Copied NonModalDialog box and changed it
+ to derive from a wxDialog but behave like the original implementation
+ which was derived from a wxFrame. wxDialog provides useful key
+ handling functionality like ESC calling OnCancel and ENTER calling
+ OnOK which is lost with wxFrame.
+
+ * Thuban/UI/mainwindow.py: Add "..." to menu items that will open
+ new dialogs.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__init__): Rearrange the
+ order that the controls are created so that tabbing works correctly.
+ (ProjFrame.OnApply): Renamed from _OnTry() to use wxDialog behaviour.
+ (ProjFrame.OnOK): Renamed from _OnOK() to use wxDialog behaviour.
+ (ProjFrame.OnCancel): Renamed from _OnClose() to use wxDialog behaviour.
+ (ProjPanel.__init__): Add "Airy" to the list of ellipsoids so we
+ can provide the "UK National Grid" as a default projection.
+ (UTMPanel.__init__): Rearrange the order that the controls are
+ created so that tabbing works correctly.
+
+2003-05-05 Bernhard Herzog <bh at intevation.de>
+
+ * extensions/thuban/wxproj.cpp: Fix some of the comments.
+ (project_point): If a map projection but no layer projection is
+ given, convert degrees to radians before applying the map
+ projection.
+
+ * Thuban/UI/tableview.py (TableGrid.disallow_messages)
+ (TableGrid.allow_messages): New methods to make it possible to
+ inhibit message sending.
+ (TableGrid.issue): Only send the message if not inhibited.
+ (LayerTableGrid.select_shape): Use the new methods to make sure
+ that no ROW_SELECTED message is sent while we're updating the
+ selected rows to match the selected shapes.
+
+2003-05-02 Jan-Oliver Wagner <jan at intevation.de>
+
+ Implementation of MemoryTable.
+
+ * Thuban/Model/table.py (MemoryTable): New. Quite simple table
+ implementation that operates on a list of tuples. All of the data
+ are kept in the memory.
+
+ * test/test_table.py (MemoryTableTest): New.
+
+ * test/test_transientdb.py (SimpleTable): Removed.
+ (TestTransientTable.test_transient_joined_table,
+ (TestTransientTable.test_transient_table_read_twice): Replaced
+ SimpleTable by MemoryTable.
+
+2003-04-30 Jonathan Coles <jonathan at intevation.de>
+
+ * Data/iceland_sample.thuban: Now contains correct projections
+ for each of the layers.
+
+ * Resources/Projections/defaults.proj: Geographic projection
+ contains unit conversion parameter.
+
+2003-04-30 Jonathan Coles <jonathan at intevation.de>
+
+ The most important part of this putback is the projection changes.
+ It should now be possible to specify the projection that a layer
+ is in and then specify a different projection for the map. The
+ projection dialog has an extra parameter for a geographic projection
+ which lets the user select if the input is in degrees or radians.
+
+ * Thuban/Model/layer.py (Layer.ShapesInRegion): Fix docstring
+ to say that the parameter is a tuple of unprojected
+ points (which is what the callers to this method were assuming).
+ Also, since the points are unprojected we need to projected them.
+
+ * Thuban/UI/legend.py (LegendTree.MoveCurrentItemUp,
+ LegendTree.MoveCurrentItemDown): If the layer or any of the layer's
+ groups are selected, move the layer up/down. Fixes RTbug #1833.
+
+ * Thuban/UI/mainwindow.py: Move menu item map_rename up.
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnSave): Add missing
+ parameter in call to SetClientData.
+ (GeoPanel): Add support for selecting the units that the
+ source data is in (Radians or Degrees).
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Optimize
+ the rendering loop by reducing the number of if's, removing the
+ unnecessary try/except block, and checking if the old group
+ is the same as the new one (which happens a lot if there is
+ no classification, or lots of shapes are in the same group).
+
+ * Thuban/UI/view.py (MapCanvas.OnPaint): Add a try/except block
+ around the redraw routine to try to catch problems that the user
+ may create by selecting invalid projections for the data set and
+ map. Clears the display if there are any problems and prints the
+ error.
+ (MapCanvas.do_redraw): Use DC.Clear() instead of drawing a filled
+ rectangle.
+
+ * extensions/thuban/wxproj.cpp (project_point): First invert the
+ supplied point (which should be in projected coordinates) using
+ the layer's projection and then project the point using the
+ map's projection.
+ (project_points): Use project_point() to project each point.
+
+2003-04-30 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.SetShapeStore): Fixed a bug:
+ don't set the Classification to None if the classfication field
+ is None (ie only a DEFAULT).
+
+2003-04-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py: Fix some typos.
+
+ * Thuban/UI/mainwindow.py (MainWindow.identify_view_on_demand): Do
+ not pop up the dialog if the selection becomes empty (this could
+ happen if e.g. a new selection is opened while the identify tool
+ is active and dialog had been closed)
+
+2003-04-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/transientdb.py (TransientTableBase.__init__): New
+ instance variable read_record_last_result
+ (TransientTableBase.read_record): Make sure reading the same
+ record twice works. The implementation uses the new instance
+ variable read_record_last_result
+
+ * test/test_transientdb.py
+ (TestTransientTable.test_transient_table_read_twice): New test
+ case for the above bug-fix.
+
+2003-04-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/common.py: Removed. No longer needed Str2Num. RTbug #1832.
+
+ * Thuban/UI/classgen.py: Remove all uses of Str2Num.
+
+ * Thuban/UI/classifier.py: Remove all uses of Str2Num.
+ (ClassTable.SetValueAsCustom): Rename keyword argument in
+ ClassGroup* constructors to match argument name.
+
+2003-04-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.Destroy): Explicitly close the
+ transient DB if it exists to make sure it doesn't leave a journal
+ file in the temp directory.
+
+ * Thuban/Model/transientdb.py (TransientDatabase.close): Set
+ self.conn to None after closing the connection to make sure it's
+ not closed twice
+
+2003-04-29 Jonathan Coles <jonathan at intevation.de>
+
+ Add a visible parameter in the layer XML tag. The default value is
+ "true". If anything other than "false" is specified we also assume
+ "true". Addresses RTbug #1025.
+
+ * Doc/thuban.dtd: Add visible parameter to a layer.
+
+ * Thuban/Model/layer.py (BaseLayer.__init__): Change default value
+ of visible from 1 to True.
+ (Layer.__init__): Change default value of visible from 1 to True.
+
+ * Thuban/Model/load.py (SessionLoader.start_layer): Read visible
+ parameter.
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Save visible
+ parameter.
+
+ * test/test_load.py: Add new test data contents_test_visible.
+ (LoadSessionTest.setUp): save test data.
+ (LoadSessionTest.testLayerVisibility): Test if the visible flag
+ is loaded correctly.
+
+ * test/test_save.py (SaveSessionTest.testSingleLayer): Add test
+ for saving an invisible layer.
+
+2003-04-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.SetMap): Look up the
+ legend dialog box and tell it to change its map to the one
+ supplied to SetMap(). Fixes RTbug #1770.
+
+2003-04-29 Bernhard Herzog <bh at intevation.de>
+
+ Next step of table implementation. Introduce a transient database
+ using SQLite that some of the data is copied to on demand. This
+ allows us to do joins and other operations that require an index
+ for good performance with reasonable efficiency. Thuban now needs
+ SQLite 2.8.0 and pysqlite 0.4.1. Older versions may work but I
+ haven't tested that.
+
+ * Thuban/Model/transientdb.py: New. Transient database
+ implementation.
+
+ * test/test_transientdb.py: New. Tests for the transient DB
+ classes.
+
+ * Thuban/Model/session.py (AutoRemoveFile, AutoRemoveDir): New
+ classes to help automatically remove temporary files and
+ directories.
+ (Session.__init__): New instance variables temp_dir for the
+ temporary directory and transient_db for the SQLite database
+ (Session.temp_directory): New. Create a temporary directory if not
+ yet done and return its name. Use AutoRemoveDir to have it
+ automatically deleted
+ (Session.TransientDB): Instantiate the transient database if not
+ done yet and return it.
+
+ * Thuban/Model/data.py (ShapefileStore.__init__): Use an
+ AutoTransientTable so that data is copied to the transient DB on
+ demand.
+ (SimpleStore): New class that simply combines a table and a
+ shapefile
+
+ * Thuban/Model/table.py (Table, DBFTable): Rename Table into
+ DBFTable and update its doc-string to reflect the fact that this
+ is only the table interface to a DBF file. Table is now an alias
+ for DBFTable for temporary backwards compatibility.
+
+ * Thuban/UI/application.py (ThubanApplication.OnExit): Make sure
+ the last reference to the session goes away so that the temporary
+ files are removed properly.
+
+ * test/test_load.py (LoadSessionTest.tearDown): Remove the
+ reference to the session to make sure the temporary files are
+ removed.
+
+2003-04-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/load.py (XMLReader.__init__, XMLReader.read): Turn
+ the __parser instance variable into a normal local variable in
+ read. It's only used there and read will never be called more than
+ once. Plus it introduces a reference cycle that keeps can keep the
+ session object alive for a long time.
+
+2003-04-29 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/proj.py (Projection): Removed Set*() methods to make
+ Projection an immutable item. Fixes RTbug #1825.
+ (Projection.__init__): Initialize instance variables here.
+ (ProjFile.Replace): New. Replace the given projection object with
+ the new projection object. This solves the problem of needing the
+ mutator Projection.SetProjection() in the ProjFrame class and
+ allows a projection to change parameters without changing its
+ location in the file.
+
+ * Thuban/UI/mainwindow.py (MainWindow.SaveSessionAs): Dialog should
+ be of type wxSAVE and should verify overwriting a file.
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnSave): Use the new
+ ProjFile.Replace() method instead of the mutator
+ Projection.SetProjection(). Also requires that we reassign the
+ client data to the new projection.
+
+ * test/test_proj.py (TestProjection.test): Test GetName() and
+ GetAllParameters()
+ (TestProjFile.test): Remove tests for Set*() methods. Add tests
+ for Replace().
+
+2003-04-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/save.py (SessionSaver.write_projection): Make sure
+ to save the name of the projection.
+
+ * test/test_save.py (SaveSessionTest.testLayerProjection): New
+ test to verify layer projections are saved correctly.
+
+2003-04-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/proj.py (Projection.SetName): Set the name
+ to "Unknown" if name is None.
+ (Projection.SetAllParameters): New. Set the projection's
+ parameter list to the one supplied.
+ (Projection.SetProjection): New. Set the projection's
+ properties to those of the supplied Projection.
+
+ * Thuban/UI/mainwindow.py (MainWindow.MapProjection): Set
+ the dialog title to include the map's title.
+ (MainWindow.LayerProjection): Set the dialog title to include
+ the layer's title.
+
+ * Thuban/UI/projdialog.py (ProjFrame.__ShowError): Consolidate
+ error dialogs into a single method call.
+ (ProjFrame.__VerifyButtons): Add more states to check.
+ (ProjFrame.__GetProjection): Return the current state of an
+ edited projection or None.
+ (ProjFrame.__FillAvailList): Remove checks for states that
+ shouldn't exist.
+ (ProjFrame._OnNew): Clear all selected items and supply
+ a projection panel if necessary.
+
+ * test/test_proj.py (TestProjFile.test): Add tests for
+ ProjFile.SetAllParameters, ProjFile.SetProjection,
+ ProjFile.SetName.
+
+2003-04-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/projdialog.py (ProjFrame.__FillAvailList): Now
+ takes an optional argument to select the current projection.
+ This does not guarantee that the item is visible due to
+ limited wxWindows functionality. Fixes RTBug #1821.
+
+2003-04-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/load.py (SessionLoader.start_projection): Remember
+ the projection name and use it when constructing the Projection
+ object.
+
+ * Thuban/Model/proj.py (Projection.__init__): Change the default
+ value for 'name' to None and then test if name is equal to None
+ in the body of the constructor. This way the caller doesn't have to
+ know what the default value should be. Namely, useful in load.py
+ where we have to pick a default value if the 'name' parameter
+ doesn't exist in the XML file.
+
+ * test/test_load.py (LoadSessionTest.testLayerProjection): New.
+ Tests a file where a layer has a projection.
+
+2003-04-25 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.TreeInfo): Add an item to the
+ tree for projection information.
+
+ * Thuban/Model/load.py (XMLReader.GetFilename): Renamed from
+ XMLReader.GetFileName.
+ (SessionLoader): Added support for loading projection tags that
+ appear inside a layer.
+
+ * Thuban/Model/proj.py (ProjFile): Document the class. Move
+ back to using a list because the order of the projections in
+ the file is important to maintain. Fixes RTbug #1817.
+
+ * Thuban/Model/resource.py: Rename calls to ProjFile.GetFileName
+ to ProjFile.GetFilename.
+
+ * Thuban/Model/save.py (SessionSaver.write_layer): Save projection
+ information.
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnAddToList): Renamed from
+ ProjFrame._OnSaveAs. Removed old dead code from previous
+ implementation.
+ (ProjFrame._OnExport): Add support for exporting more than one
+ projection to a single file.
+ (ProjFrame.__FillAvailList): use string formatting (% operator)
+ to build strings that are (partly) translated. Fixes RTbug #1818.
+
+ * test/test_proj.py (TestProjFile.test): New. Tests the base ProjFile
+ class.
+
+2003-04-24 Bernhard Herzog <bh at intevation.de>
+
+ * po/es.po: Updated Spanish translation by Daniel Calvelo Aros
+
+ * po/fr.po: New. French translation by Daniel Calvelo Aros
+
+ * Thuban/UI/projdialog.py (ProjFrame._OnSaveAs): Don't translate
+ empty strings.
+
+2003-04-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.GetProjection): New. Needed to
+ implement the interface that the ProjFrame dialog expects.
+
+ * Thuban/Model/proj.py (Projection.SetName): New. Allows the
+ name of the projection to be changed.
+ (ProjFile): Use a dictionary instead of a list so that removing
+ projections is easier and we are sure about uniqueness.
+ (ProjFile.Remove): Remove the given projection object.
+
+ * Thuban/Model/resource.py (GetSystemProjFiles, GetUserProjFiles):
+ Return a list with only one projection file instead of searching for
+ any projection file. This simplifies many things if the user can
+ only have one system file and one user file.
+
+ * Thuban/UI/classgen.py: Change all references to
+ genCombo to genChoice.
+
+ * Thuban/UI/mainwindow.py: Add a Projection option under the
+ layer menu.
+ (MainWindow.LayerProjection): New. Open up a projection window
+ for a layer.
+
+ * Thuban/UI/projdialog.py: Large changes to how the dialog is
+ laid out. Use three panels instead of one. One for the list of
+ projections, one for the edit controls, and one for the buttons.
+ Fixed resizing problems so that the dialog resizes correctly
+ when the projection panel changes. Added import/export, save, and
+ new buttons/functionality.
+
+2003-04-24 Bernhard Herzog <bh at intevation.de>
+
+ First step towards table management. Introduce a simple data
+ abstraction so that we replace the data a layer uses more easily
+ in the next step.
+
+ * Thuban/Model/data.py: New file with a simple data abstraction
+ that bundles shapefile and dbffile into one object.
+
+ * Thuban/Model/session.py (Session.OpenShapefile): New method to
+ open shapefiles and return a shape store object
+
+ * Thuban/Model/layer.py (Layer.__init__): Pass the data as a store
+ object instead of a shapefile filename. This introduces a new
+ instance variable store holding the datastore. For intermediate
+ backwards compatibility keep the old instance variables.
+ (open_shapefile): Removed. No longer needed with the shape store.
+ (Layer.SetShapeStore, Layer.ShapeStore): New methods to set and
+ get the shape store used by a layer.
+ (Layer.Destroy): No need to explicitly destroy the shapefile or
+ table anymore.
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddLayer)
+ (MainWindow.AddLayer): Use the session's OpenShapefile method to
+ open shapefiles
+
+ * Thuban/Model/load.py (ProcessSession.start_layer): Use the
+ session's OpenShapefile method to open shapefiles
+
+ * test/test_classification.py
+ (TestClassification.test_classification): Use the session's
+ OpenShapefile method to open shapefiles and build the filename in
+ a more platform independed way
+
+ * test/test_layer.py (TestLayer.setUp, TestLayer.tearDown):
+ Implement to have a session to use in the tests
+ (TestLayer.test_arc_layer, TestLayer.test_polygon_layer)
+ (TestLayer.test_point_layer, TestLayer.test_empty_layer): Use the
+ session's OpenShapefile method to open shapefiles
+ (TestLayerLegend.setUp): Instantiate a session so that we can use
+ it to open shapefiles.
+ (TestLayerLegend.tearDown): Make sure that all references to
+ layers and session are removed otherwise we may get a resource
+ leak
+
+ * test/test_map.py (TestMapAddLayer.test_add_layer)
+ (TestMapWithContents.setUp): Instantiate a session so that we can
+ use it to open shapefiles.
+ (TestMapWithContents.tearDown): Make sure that all references to
+ layers, maps and sessions are removed otherwise we may get a
+ resource leak
+ ("__main__"): use support.run_tests() so that more info about
+ uncollected garbage is printed
+
+ * test/test_save.py (SaveSessionTest.testSingleLayer): Use the
+ session's OpenShapefile method to open shapefiles
+ ("__main__"): use support.run_tests() so that more info about
+ uncollected garbage is printed
+
+ * test/test_selection.py (TestSelection.tearDown): Make sure that
+ all references to the session and the selection are removed
+ otherwise we may get a resource leak
+ (TestSelection.get_layer): Instantiate a session so that we can
+ use it to open shapefiles.
+ ("__main__"): use support.run_tests() so that more info about
+ uncollected garbage is printed
+
+ * test/test_session.py (TestSessionBase.tearDown)
+ (TestSessionWithContent.tearDown): Make sure that all references
+ to the session and layers are removed otherwise we may get a
+ resource leak
+ (TestSessionWithContent.setUp): Use the session's OpenShapefile
+ method to open shapefiles
+
+2003-04-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/load.py (XMLReader.read): Should have been checking
+ if the file_or_filename object had the 'read' attribute.
+
+2003-04-23 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/resource.py: Fixes RTbug #1813.
+ (ReadProjFile): Add documentation about which exceptions are raised.
+ Always pass the exceptions up to the caller.
+ (GetProjFiles): If the directory can't be read return an empty list.
+ If any of the proj files can't be read skip that file and go
+ on to the next one.
+
+ * test/test_proj.py: Added test cases to handle nonexistent files,
+ unreadable files, and files that don't parse correctly.
+
+2003-04-23 Jonathan Coles <jonathan at intevation.de>
+
+ Projection dialog. Allows the user to select from a list
+ of projection templates and optionally edit them and save new ones.
+
+ * Thuban/UI/projdialog.py (ProjFrame): New. Main dialog.
+ (ProjPanel): Base class for projection specific panels.
+ (TMPanel): Projection panel for Transverse Mercartor.
+ (UTMPanel): Projection panel for Universal Transverse Mercartor.
+ (LCCPanel): Projection panel for Lambert Conic Conformal.
+ (GeoPanel): Projetion panel for Geographic Projection.
+
+2003-04-23 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/load.py (XMLReader): Renamed from XMLProcessor to
+ promote symmetry. There now exists XMLReader and XMLWriter.
+ (XMLReader.read): New. Call to read the given file descriptor or
+ filename.
+ (XMLReader.close): New. Make sure the file is closed.
+ (XMLReader.GetFileName): New. Return just the file name that is being
+ read from.
+ (XMLReader.GetDirectory): New. Return just the directory of the file
+ that is being read.
+ (XMLReader.AddDispatchers): New. Take a dictionary which contains
+ the names of functions to call as the XML tree is parsed.
+ (XMLReader.startElementNS): Updated to use new dispatcher dictionary.
+ (XMLReader.endElementNS): Updated to use new dispatcher dictionary.
+ (SessionLoader): Removed class variables start_dispatcher and
+ end_dispatcher since this functionality is now part of a class
+ instance. Fixes RTbug #1808.
+ (SessionLoader.__init__): Add dispatcher functions.
+ (load_xmlfile): Code was moved into the XMLReader.read().
+ (load_session): Use modified SessionLoader.
+
+ * Thuban/Model/map.py (Map.GetProjection): New. Returns the
+ map's projection.
+
+ * Thuban/Model/proj.py (Projection.GetParameters): Renamed to
+ GetAllParameters.
+ (Projection.GetParameter): Returns the value for the given parameter.
+
+ * Thuban/Model/resource.py: Use XMLReader and XMLWriter.
+ (GetProjFiles): Renamed from GetProjections. Now returns a list
+ of ProjFile objects.
+ (GetSystemProjFiles): Renamed from GetSuppliedProjections. Returns
+ a list of ProjFile objects whose files are not user defined.
+ (GetUserProjFiles): Renamed from GetUserProjections. Returns a
+ list of ProjFile objects whose files are user defined.
+ (ProjFileReader): Extend new XMLReader.
+
+ * Thuban/Model/save.py (XMLWriter): Renamed from XMLSaver to
+ promote symmetry.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__): Use a wxChoice
+ control instead of a wxComboBox. wxChoice controls do not generate
+ events as the uses highlights possible choices which fixes problems
+ with resizing the dialog when the use selects an option.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Use a wxChoice
+ control instead of a wxComboBox.
+
+ * Thuban/UI/mainwindow.py (MainWindow.Projection): Use new projection
+ dialog.
+
+ * test/test_proj.py (TestProjection.test): New tests for GetParameter
+ method.
+
+2003-04-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Remove some unused imports and global
+ constants
+
+ * Thuban/UI/identifyview.py (IdentifyListCtrl.selected_shape)
+ (IdentifyGridCtrl.selected_shape): Use table, not shapetable.
+
+2003-04-17 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py: Don't import LAYER_LEGEND_CHANGED.
+ (Layer): Update doc-string since LAYER_LEGEND_CHANGED is not used
+ anymore.
+ (Layer.BoundingBox, Layer.GetFieldType, Layer.NumShapes)
+ (Layer.ShapeType, Layer.Shape): No need to call
+ self.open_shapefile since it's always called in __init__
+
+ * Thuban/UI/application.py (ThubanApplication.MainLoop): Removed.
+ In wxPython 2.4 there's no need to extend MainLoop anymore since
+ wxPython itself makes sure OnExit is called.
+
+2003-04-16 Jonathan Coles <jonathan at intevation.de>
+
+ Initial putback of projection management code. Includes new
+ classes to read and write projection files. The current load
+ and save classes were abstracted a bit so they could be reused.
+ The Projection class was extended to provide new methods and
+ have a name.
+
+ * Thuban/Model/load.py (XMLProcessor): New. Contains all the
+ general XML reading methods that were part of ProcessSession.
+
+ * Thuban/Model/proj.py (Projection.__init__): Accepts an optional
+ name.
+ (ProjFile): New. Represents a file that contains projection
+ information.
+
+ * Thuban/Model/resource.py: New. Contains general utilities
+ for read and writing projection files.
+
+ * Thuban/Model/save.py (XMLSaver): New. Contains all the
+ general XML writing methods that were part of SessionSaver.
+ (SessionSaver): Renamed from Saver.
+
+ * test/test_proj.py: New test cases for the projection
+ file read and write functions.
+
+2003-04-16 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Use repr() around values
+ in the ClassGroup*.__repr__() methods so it is clearer when
+ a value is a string and when it is a number.
+
+ * test/test_load.py: Rework the classification test to test
+ that we can load old files.
+ (testLabels): Test a file where the groups have labels.
+
+2003-04-16 Bernhard Herzog <bh at intevation.de>
+
+ Safer implementation of the performance enhancements of the
+ low-level renderer:
+
+ * extensions/thuban/wxproj.cpp (extract_projection)
+ (extract_pointer): Rename extract_projection to extract_pointer
+ and redefine its purpose to return the pointer stored in a CObject
+ returned by the object's cobject method. Update all callers.
+ (s_draw_info, free_draw_info, draw_polygon_init): Implement the
+ handling of these low-level parameters so that each s_draw_info
+ instance is handled as a CObject at python level that also
+ contains real references to the actual python objects which
+ contain the values in the struct. Add free_draw_info as the
+ destructor.
+ (draw_polygon_shape): Add the py_draw_info parameter which must a
+ cobject containing an s_draw_info pointer.
+
+ * Thuban/UI/renderer.py (MapRenderer.polygon_render_param): New
+ method to instantiat the low-level render parameter
+ (MapRenderer.draw_shape_layer): Use the new method. Remove some
+ commented out code.
+ (MapRenderer.draw_polygon_shape): Make the first parameter not the
+ layer but the low-level render parameter
+ (ScreenRenderer.draw_shape_layer): Use the low-level render
+ parameter.
+
+2003-04-15 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Implemented __repr__ for
+ the ClassGroup* classes to make debugging a bit easier.
+ (ClassGroup.SetLabel): Check that the string is an instance
+ of StringTypes not StringType. Accounts for Unicode strings.
+
+ * Thuban/Model/color.py: Implemented __repr__ to make
+ debugging a bit easier.
+
+ * Thuban/Model/save.py (Saver.write_classification): Need to
+ save the group label.
+
+ * test/test_load.py (testClassification): New. Loads the
+ iceland_sample_test.thuban file and checks if it was loaded
+ correctly.
+
+2003-04-15 Jonathan Coles <jonathan at intevation.de>
+
+ * extensions/thuban/wxproj.cpp (draw_polygon_init): New. Used
+ to improve rendering performance by initializing the variables
+ that are not change each time draw_polygon_shape() is called.
+ The values are stored in a global struct draw_info.
+ (draw_polygon_shape): Removed initialization code that is
+ now in draw_polygon_init().
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Make
+ drawing initialization call to draw_polygon_init()
+ (MapRenderer.draw_polygon_shape): Use new signature of
+ draw_polygon_shape.
+
+ * Thuban/UI/classgen.py (GenUniformPanel): Fix spin control
+ weirdness by setting the range to (1, maxint).
+
+ * Thuban/Model/classification.py (ClassGroupProperties): Make
+ instance variables private and optimize comparison operator
+ by first checking if the color references are the same.
+ (ClassGroupSingleton): Make instance variables private.
+ (ClassGroupRange): Make instance variables private.
+
+ * HOWTO-Release: Filled in missing steps for releasing packages.
+
+2003-04-15 Bernhard Herzog <bh at intevation.de>
+
+ First stab at internationalized messages:
+
+ * Thuban/__init__.py (_): Implement the translation function for
+ real using the python gettext module.
+
+ * Thuban/UI/classifier.py (ClassTable.GetRowLabelValue): Don't
+ translate empty strings.
+
+ * Thuban/UI/application.py (ThubanApplication.read_startup_files):
+ Add a missing space to a warning message
+
+ * po/README: New. Notes about the management of the translation
+ files.
+
+ * po/Makefile: New. Makefile to help manage the translation files.
+
+ * po/es.po: New. Spanish translation by Daniel Calvelo Aros
+
+ * MANIFEST.in: Include the *.mo files in Resources/Locale and the
+ translations and support files in po/
+
+ * setup.py (data_files): Add the *.mo files to the data_files too
+
+ * README: Add note about the translations when building from CVS
+
+2003-04-14 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/dock.py: Fixes some window resizing problems most
+ noticable under windows. Always assume the button bitmaps will
+ be there. Code clean up.
+ (DockabelWindow.Dock, DockableWindow.UnDock): Force all the
+ images for the dock/undock button to the same images.
+ Work around for RTbug #1801.
+
+ * Thuban/UI/legend.py (LegendPanel.__init__): The toolbar should
+ be allowed to grow within the sizer. Fixes a bug under Windows
+ where the toolbar wasn't being drawn.
+
+2003-04-14 Frank Koormann <frank.koormann at intevation.de>
+
+ * Resources/Bitmaps/dock_12.xpm, Resources/Bitmaps/undock_12.xpm:
+ Updated design to try to make the button functionality more
+ transparent.
+
+2003-04-14 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/legend.py (LegendPanel.__init__): Call Create() to
+ finalize the intialization of the panel.
+
+ * Thuban/UI/dock.py (DockPanel.Create): New. Finalizes the
+ creation of the panel. Should be the last thing called in the
+ initializer of a subclass.
+
+ * Thuban/UI/classgen.py (ClassGenDialog.__init__): Actively
+ set the current selections in the combo boxes. This is needed
+ under Windows.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Add a top
+ level panel to the dialog so that the background colors are
+ consistent under Windows.
+
+2003-04-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classgen.py: Change color ramps to start at white
+ not black.
+
+ * Thuban/UI/legend.py: Enable/disable the legend buttons when
+ the legend changes. Fixes RTbug #1793.
+
+ * test/test_classification.py: Added test for copying of
+ classifications.
+
+2003-04-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/resource.py: New. Centralize the loading of resources
+ such as bitmaps.
+
+ * Thuban/UI/classgen.py (GenUniquePanel.__init__): Reordered buttons,
+ added images to the move buttons, added 'reverse' button.
+ (CustomRampPanel.__init__): Added images to the move buttons.
+ (GreyRamp): New. Generates a ramp from white to black.
+ (HotToColdRamp): New. Generates a ramp from cold to hot colors.
+
+ * Thuban/UI/classifier.py: Refactored ID's from ID_CLASSIFY_* to
+ ID_PROPERTY_*.
+ (Classifier.__init__): Minor changes to the layout.
+ (Classifier._OnTitleChanged): Listen for when the user edits the
+ title and update the dialog's title and the layer's title.
+
+ * Thuban/UI/dock.py: Use new bitmaps for the control buttons.
+
+ * Thuban/UI/legend.py: Use new bitmaps for the control buttons.
+ (LegendTree._OnMsgLayerTitleChanged): Change the displayed title
+ if the layer's title changes.
+
+ * Thuban/UI/mainwindow.py: Added new menu item and associated code
+ to open a dialog to rename the map.
+ (MainWindow): Use new resource class to import bitmaps.
+
+2003-04-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Resources/Bitmaps/close_12.xpm, Resources/Bitmaps/dock_12.xpm,
+ Resources/Bitmaps/group_use.xpm, Resources/Bitmaps/group_use_all.xpm,
+ Resources/Bitmaps/group_use_none.xpm,
+ Resources/Bitmaps/group_use_not.xpm,
+ Resources/Bitmaps/hide_layer.xpm,
+ Resources/Bitmaps/layer_properties.xpm,
+ Resources/Bitmaps/lower_layer.xpm, Resources/Bitmaps/raise_layer.xpm,
+ Resources/Bitmaps/show_layer.xpm, Resources/Bitmaps/undock_12.xpm:
+ New.
+
+2003-04-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: (ClassGroupRange.__init__):
+ Should pass group to ClassGroup constructor.
+
+2003-04-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: (ClassGroup): Move all the common
+ methods of the derived classes ([Set|Get]Properties(), __eq__, __ne__)
+ here. Implement SetVisible(), IsVisible().
+ (ClassGroup.__init__): Add group parameter which acts as a copy
+ constructor.
+
+ * Thuban/UI/classifier.py (ClassTable): Add a new column for the
+ "Visible" check boxes.
+ (Classifier): Rename the buttons and refactor the code to match
+ the new labels.
+
+ * Thuban/UI/legend.py: Classify button is now called "Properties".
+ Refactored the code to change variable names.
+ (LegendTree.__FillTreeLayer): Only list a group if it is visible.
+
+ * Thuban/UI/mainwindow.py: MainWindow.OpenClassifier renamed to
+ MainWindow.OpenLayerProperties. MainWindow.LayerEditProperties
+ renamed to MainWindow.LayerEditProperties.
+ (MainWindow.ToggleLegend): Don't include map name in legend title.
+ (MainWindow.SetMap): Added the map name to the window title.
+ (MainWindow.LayerFillColor, MainWindow.LayerTransparentFill,
+ MainWindow.LayerOutlineColor, MainWindow.LayerNoOutline): Removed.
+ Functionality is found in the layer properties dialog.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Only
+ draw visible groups.
+
+2003-04-09 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classgen.py: Modifications to allow simple
+ addition and selection of new color schemes.
+ (MonochromaticRamp): New. Generates a ramp between two colors.
+ (RedRamp): New. Generates a ramp of all red.
+ (GreenRamp): New. Generates a ramp of all green.
+ (BlueRamp): New. Generates a ramp of all blue.
+
+2003-04-09 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py (Classification.__deepcopy__):
+ Need to copy over field and fieldType attributes.
+
+ * Thuban/Model/table.py (Table.field_range): New. Retrive the
+ maximum and minimum values over the entire table for a given
+ field.
+ (Table.GetUniqueValues): New. Retrieve all the unique values
+ in the table for a given field.
+
+ * Thuban/UI/classgen.py: Renamed GenRangePanel to GenUniformPanel.
+ (GenUniquePanel): New. Controls to allow the user to select
+ which unique field values they would like in the classification.
+ (CustomRampPanel): Code that was in ClassGenDialog that allows
+ the user to select the properties for a custom ramp.
+ (ClassGenerator.GenUniformDistribution): Was called GenerateRanges.
+
+ * Thuban/UI/classifier.py: Removed a lot of debugging code.
+ (Classifier._SetClassification): Callback method so that the
+ class generator can set the classification in the grid.
+ (ClassGroupPropertiesCtrl): New. Encapsulates the drawing and
+ editing of a group properties class into a wxWindows control.
+
+ * Thuban/UI/dock.py: It was decided that if the user closes
+ a dockable window the window should simply hide itself. That
+ way if the user wants to show the dock again it appears in the
+ same place as it was when it was closed.
+ (DockableWindow.Destroy): Call renamed method OnDockDestroy().
+ (DockableWindow._OnButtonClose): Hide the window instead of
+ destroying it.
+ (DockableWindow._OnClose): Hide the window instead of
+ destroying it.
+
+ * Thuban/UI/legend.py (LegendTree): Use a private method to
+ consistently set the font and style of the text. Fixes RTbug #1786.
+
+ * Thuban/UI/mainwindow.py: Import just the Classifier class.
+
+2003-04-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (main_menu): Move the toggle_legend item
+ to the map module
+
+2003-04-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.ShowSessionTree): Removed in
+ favor of ToggleSessionTree
+ (MainWindow.ToggleSessionTree): New method to toggle visibility of
+ the session tree.
+ (MainWindow.SessionTreeShown): New method to return whether the
+ session tree is currently shown.
+ (MainWindow.ToggleLegend): New method to toggle visibility of the
+ legend
+ (MainWindow.ShowLegend): Implement in terms of ToggleLegend and
+ LegendShown
+ (MainWindow.LegendShown): New method to return whether the legend
+ is currently shown.
+ (_method_command): Add checked parameter so we can define check
+ menu items
+ (_has_tree_window_shown, _has_legend_shown): Use the appropriate
+ mainwindow methods.
+ (show_session_tree, show_legend commands): Removed.
+ (toggle_session_tree, toggle_legend commands): New commands to
+ toggle the visibility of the dialogs
+
+2003-04-07 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classgen.py: Fix Windows problem.
+
+ * Thuban/UI/dock.py: Fix Windows problem.
+
+ * Thuban/UI/mainwindow.py: Use False instead of false.
+ (MainWindow.ShowLegend): Remove unnecessary switch parameter.
+
+2003-04-07 Jonathan Coles <jonathan at intevation.de>
+
+ Since we now say that the order of the groups in a classification
+ matters, it makes sense to be able to manipulate that order. Most
+ of the changes to Thuban/Model/classification.py are to that end.
+
+ * Thuban/Model/classification.py (Classification.AppendGroup,
+ Classification.InsertGroup, Classification.ReplaceGroup,
+ Classification.RemoveGroup, Classification.GetGroup): Do as the
+ names imply.
+ (Classification.FindGroup): This was called GetGroup, but GetGroup
+ takes an index, while FindGroup takes a value.
+ (Classification.__deepcopy__): Copy all the groups, BUT NOT THE LAYER
+ REFERENCE. Currently there is a cyclic reference between the layer
+ and its classification. If the classification doesn't need to know
+ its owning layer we can change this, since it may make sense to be
+ able to use the same classification with different layers.
+
+ * Thuban/Model/load.py: Use Classification.AppendGroup(), not AddGroup()
+
+ * Thuban/UI/classgen.py: Use Classification.AppendGroup(),
+ not AddGroup()
+
+ * Thuban/UI/classifier.py: Now that we can depend on the order in
+ a Classification and have methods to manipulate that order we don't
+ need to use our own data structures in the grid. We can simply make
+ the grid/table access the information they need from a copy of
+ the classification object.
+ (Classifier._OnCloseBtn): Event handler for when the user clicks
+ 'Close'. This is needed so if the user applies changes and then
+ continues to change the table the user has the option of discarding
+ the most recent changes and keeping what they applied.
+
+ * Thuban/UI/mainwindow.py: Put "Show Legend" and "Show Session Tree"
+ into the same group.
+
+ * extensions/thuban/wxproj.cpp (check_version): If Thuban is compiled
+ with a really old version of proj, PJ_VERSION won't even be defined.
+ If it isn't defined then just compile so that the function always
+ returns Py_False.
+
+ * test/test_classification.py: Fix tests to use the renamed methods.
+ Still need to write tests for the new methods.
+
+2003-04-04 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier.__SelectField): Move the
+ call to SetSelection out of the method and before the call
+ to __SelectField in __init__. This prevents a recursion of events
+ when _OnFieldSelect is triggered by the user.
+
+2003-04-04 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Rename Color.None to
+ Color.Transparent.
+ (ClassGroupProperties.SetLineColori, ClassGroupProperties.SetFill):
+ Don't bother copying the color, since Colors are immutable.
+
+ * Thuban/Model/color.py, Thuban/Model/layer.py, Thuban/Model/load.py,
+ Thuban/UI/classifier.py, Thuban/UI/mainwindow.py,
+ Thuban/UI/renderer.py, Thuban/UI/view.py:
+ Rename Color.None to Color.Transparent.
+
+ * test/test_classification.py, test/test_load.py: Rename Color.None
+ to Color.Transparent.
+
+2003-04-04 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Fix assert calls.
+ (ClassGroupProperties.SetLineColor, ClassGroupProperties.SetFill):
+ Copy the color parameter rather than hold onto a reference.
+
+ * Thuban/Model/color.py (Color.__copy__, Color.__deepcopy): Copy
+ the color object.
+ (NoColor.__copy__, NoColor.__deepcopy): Return 'self' so that we
+ are sure there exists only one refernce to Color.None in the system.
+ This allows us to use 'is' rather than the comparision functions.
+
+ * Thuban/Model/save.py: Fix assert calls.
+
+ * Thuban/UI/classifier.py: Fix assert calls.
+ (ClassGrid._OnCellDClick): Call up to the classifier to open the
+ dialog to edit the groups properties.
+ (ClassGrid._OnCellResize): Make sure that the scollbars are drawn
+ correctly if a cell is resized.
+ (ClassTable.SetClassification): New. Changes the classification
+ that is in the table.
+ (ClassTable.__SetRow): Allow groups to be prepended.
+ (Classifier): New code for opening the EditProperties and
+ GenerateRanges dialogs.
+ (SelectPropertiesDialog.__GetColor): Only set the color in the
+ color dialog if the current color is not None.
+
+ * Thuban/UI/dock.py: Fix assert calls.
+
+ * Thuban/UI/legend.py: Fix assert calls.
+
+ * Thuban/UI/renderer.py: Fix assert calls.
+
+ * Thuban/UI/classgen.py (ClassGenDialog): Dialog for generating
+ classifications.
+ (GenRangePanel): Panel specific to range generation.
+ (GenSingletonPanel): Panel specific to singleton generation.
+ (ClassGenerator): Class responsible for actually generating
+ the classification from the data gathered in the dialog box.
+ (PropertyRamp): Generates properties whose values range from
+ a starting property to an ending property.
+
+2003-04-03 Bernhard Herzog <bh at intevation.de>
+
+ * test/support.py (print_garbage_information): New function that
+ prints information about still connected messages and memory
+ leaks.
+ (run_suite): Removed.
+ (run_tests): New function for use as a replacement of
+ unittest.main in the test_* files. This one calls
+ print_garbage_information at the end.
+
+ * test/runtests.py (main): Use support.print_garbage_information
+
+ * test/test_layer.py: Use support.run_tests instead of
+ unittest.main so we get memory leak information
+ (TestLayer.test_arc_layer, TestLayer.test_polygon_layer)
+ (TestLayer.test_point_layer, TestLayer.test_empty_layer)
+ (TestLayerLegend.test_visibility): Call the layer's Destroy method
+ to fix a memory leak.
+
+ * test/test_classification.py: Use support.run_tests instead of
+ unittest.main so we get memory leak information
+ (TestClassification.test_classification): Call the layer's Destroy
+ method to fix a memory leak.
+
+2003-04-02 Bernhard Herzog <bh at intevation.de>
+
+ * extensions/thuban/wxproj.cpp (check_version, check_version_gtk):
+ Handle the reference counts of the return value and errors in
+ PyArg_ParseTuple correctly.
+
+ * Thuban/UI/application.py (ThubanApplication.OpenSession): Make
+ sure the filename is absolute to avoid problems when saving the
+ session again
+
+ * Thuban/Model/table.py: Remove unnecessary import. Fix a typo.
+
+2003-04-01 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_point_shape): Check
+ that there actually are points in the returned list of points
+ before trying to index into the list. The list may be empty if
+ the shape is a Null Shape.
+
+2003-04-01 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_map.py: Don't use from <module> import *
+
+2003-04-01 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/session.py: Use LAYER_CHANGED instead of
+ LAYER_LEGEND_CHANGED
+
+ * Thuban/UI/dock.py (DockableWindow._OnButtonClose): Call
+ self.Destroy() to close the window after yesterday's changes.
+
+ * test/test_map.py, test/test_session.py: Fix messages that
+ are sent from maps and layers.
+
+2003-03-31 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py: Commented out some debugging statements.
+ (ClassDataPreviewer.Draw): Draw rectangles for polygon layers per
+ RTbug #1769.
+
+ * Thuban/UI/dock.py (DockableWindow.UnDock): Restore size and
+ position (although position doesn't work yet under GTK).
+ (DockableWindow.Destroy): New. Called when the window must be
+ closed. Namely needed when the DockFrame closes and must close
+ its children.
+ (DockFrame): Listen for EVT_CLOSE and destroy all children.
+
+ * Thuban/UI/legend.py (LegendPanel.Destroy): New. Cleans up
+ when then window is told to close.
+ (LegendTree._OnMsgLayerChanged): Fixes a seg fault bug. See
+ comment in source for more info.
+
+ * Thuban/UI/main.py: Show the legend by default when Thuban starts.
+
+ * Thuban/UI/mainwindow.py: Renamed OnClose to _OnClose for
+ symmetry with other such methods.
+ (MainWindow.ShowLegend): Show the legend docked by default.
+
+2003-03-28 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py: Support for highlighting a specific
+ group within the grid when the classification dialog is opened.
+ Also contains a lot of debugging printouts which will later
+ be removed.
+
+ * Thuban/UI/dock.py: Complete rework on the dock code so that
+ that it is fairly removed from the rest of the Thuban application.
+ It is easy to add new docks which the rest of the program having
+ to be aware of them.
+
+ * Thuban/UI/legend.py: Modifications to support selecting a
+ specific group in the classification dialog. Changed how layers
+ are drawn when the layer is visible/invisible.
+
+ * Thuban/UI/mainwindow.py: Removed legend specific code and
+ replaced it with calls to the new dock code.
+
+ * Thuban/UI/renderer.py (MapRenderer.__init__): Added assert
+ to check if scale > 0. Trying to track down a divide by zero.
+
+2003-03-26 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/legend.py: Removed unnecessary LegendDialog class.
+ (LegendPanel): Removed _OnDock()/_OnUnDock() methods which are
+ now part of DockableWindow.
+ (LegendPanel.DoOnSelChanged): Select the current layer in the
+ map.
+ (LegendTree._OnSelChanged): Call LegendPanel.DoOnSelChanged()
+ with the selected layer and/or group.
+
+2003-03-26 Jonathan Coles <jonathan at intevation.de>
+
+ This putback contains the code for dockable windows. There is
+ no support in wxWindows as of this date for windows that can
+ attach themselves to other windows.
+
+ The current model contains a DockableWindow which has a parent
+ window for when it is detached and a dock window that it puts
+ its contents in when it is docked. The contents of a DockableWindow
+ must be a DockPanel. DockPanel itself derives from wxPanel.
+
+ * Thuban/Model/layer.py (Layer.ClassChanged): Send a LAYER_CHANGED
+ message, not a LAYER_LEGEND_CHANGED message.
+
+ * Thuban/Model/map.py (Map): Forward LAYER_CHANGED messages.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Use wxADJUST_MINSIZE
+ as one of the style properties for the fieldTypeText item to
+ be sure that its size is correct when the text changes.
+
+ * Thuban/UI/dock.py: New. Classes for the DockPanel and
+ DockableWindow.
+
+ * Thuban/UI/legend.py: Added some more buttons and made the
+ LegendPanel a DockPanel.
+
+ * Thuban/UI/mainwindow.py: Added sash windows to the main window
+ and supporting functions for manipulating the sashes.
+ (MainWindow.ShowLegend): Create a DockableWindow with the
+ LegendPanel as the contents.
+
+ * Thuban/UI/messages.py: Added DOCKABLE_* messages
+
+ * Thuban/UI/view.py (MapCanves.SetMap): Listen for LAYER_CHANGED,
+ not LAYER_LEGEND_CHANGED, messages.
+
+2003-03-25 Jonathan Coles <jonathan at intevation.de>
+
+ * setup.py: Added custom script bdist_rpm_build_script so that
+ when the rpm is built the path to wx-config is correct.
+
+ * setup.cfg: Added line saying to use the custom build script
+
+2003-03-20 Jonathan Coles <jonathan at intevation.de>
+
+ Initial implementation of the Legend.
+
+ * Thuban/UI/legend.py: New. Creates a window that shows the map's
+ Legend information and allows the user to add/modify classifications
+ and how the layers are drawn on the map.
+
+ * setup.py: New command 'build_docs' which currently uses
+ happydoc to generate html documentation for Thuban.
+
+ * Thuban/Model/classification.py (ClassGroup.GetDisplayText): New.
+ Returns a string which is appropriately describes the group.
+
+ * Thuban/Model/layer.py (Layer.SetClassification): Generate a
+ LAYER_CHANGED event instead of a LAYER_LEGEND_CHANGED event.
+
+ * Thuban/Model/map.py (Map): Rename messages and use new, more
+ specific, messages.
+
+ * Thuban/Model/messages.py: New message to indicate that a layer's
+ data has changed (LAYER_CHANGED). New map messages to indicate
+ when layers have been added/removed/changed or if the stacking order
+ of the layers has changed.
+
+ * Thuban/Model/session.py: Rename and use new messages.
+
+ * Thuban/UI/classifier.py: Remember if any changes have actually
+ been applied so that if the dialog is cancelled without an application
+ of changes we don't have to set a new classification.
+ (ClassDataPreviewer): Pulled out the window specific code and put it
+ ClassDataPreviewWindow. ClassDataPreviewer can then be used to draw
+ symbols on any DC.
+
+ * Thuban/UI/mainwindow.py: New code to open the legend.
+
+ * Thuban/UI/view.py: Use new message names.
+
+2003-03-19 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/main.py (verify_versions): New. Checks the versions
+ of Python, wxPython, and some other libraries.
+
+ * extensions/thuban/wxproj.cpp (check_version): Checks the given
+ version against what wxproj was compiled with.
+ (check_version_gtk): If wxproj was compiled with gtk then check
+ the given version against the version of the gtk library
+ currently being used.
+
+2003-03-14 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_command.py: Run the tests when the module is run as a
+ script
+
+2003-03-14 Bernhard Herzog <bh at intevation.de>
+
+ Implement selection of multiple selected shapes in the same layer:
+
+ - Introduce a new class to hold the selection. This basically
+ replaces the interactor which was nothing more than the
+ selection anyway. A major difference is of course that the new
+ selection class supports multiple selected shapes in one layer
+
+ - Move the object that represents the selection from the
+ application to the canvas. The canvas is a better place than the
+ application because the selection represents which shapes and
+ layer of the map displayed by the canvas are selected and
+ affects how the map is drawn.
+
+ - Make the selection and its messages publicly available through
+ the mainwindow.
+
+ - The non-modal dialogs do not get a reference to the interactor
+ anymore as they can simply refer to their parent, the
+ mainwindow, for the what the interactor had to offer.
+
+ * Thuban/UI/selection.py: New module with a class to represent the
+ selection.
+
+ * Thuban/UI/messages.py (SELECTED_TABLE, SELECTED_MAP): Remove
+ these unused messages
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit)
+ (ThubanApplication.OnExit, ThubanApplication.SetSession): The
+ interactor is gone now.
+ (ThubanApplication.CreateMainWindow): There is no interactor
+ anymore so we pass None as the interactor argument for now for
+ compatibility.
+
+ * Thuban/UI/view.py (MapCanvas.delegated_messages)
+ (MapCanvas.Subscribe, MapCanvas.Unsubscribe): In Subscribe and
+ Unsubscribe, delegate messages according to the delegated_messages
+ class variable.
+ (MapCanvas.__getattr__, MapCanvas.delegated_methods): Get some
+ attributes from instance variables as described with the
+ delegated_methods class variable.
+ (MapCanvas.__init__): New instance variable selection holding the
+ current selection
+ (MapCanvas.do_redraw): Deal with multiple selected shapes. Simply
+ pass them on to the renderer
+ (MapCanvas.SetMap): Clear the selection when a different map is
+ selected.
+ (MapCanvas.shape_selected): Simple force a complete redraw. The
+ selection class now takes care of only issueing SHAPES_SELECTED
+ messages when the set of selected shapes actually does change.
+ (MapCanvas.SelectShapeAt): The selection is now managed in
+ self.selection
+
+ * Thuban/UI/mainwindow.py (MainWindow.delegated_messages)
+ (MainWindow.Subscribe, MainWindow.Unsubscribe): In Subscribe and
+ Unsubscribe, delegate messages according to the delegated_messages
+ class variable.
+ (MainWindow.delegated_methods, MainWindow.__getattr__): Get some
+ attributes from instance variables as described with the
+ delegated_methods class variable.
+ (MainWindow.__init__): The interactor as ivar is gone. The
+ parameter is still there for compatibility. The selection messages
+ now come from the canvas.
+ (MainWindow.current_layer, MainWindow.has_selected_layer):
+ Delegate to the the canvas.
+ (MainWindow.LayerShowTable, MainWindow.Classify)
+ (MainWindow.identify_view_on_demand): The dialogs don't need the
+ interactor parameter anymore.
+
+ * Thuban/UI/tableview.py (TableFrame.__init__)
+ (LayerTableFrame.__init__, LayerTableFrame.OnClose)
+ (LayerTableFrame.row_selected): The interactor is gone. It's job
+ from the dialog's point of view is now done by the mainwindow,
+ i.e. the parent. Subscribe to SHAPES_SELECTED instead
+ of SELECTED_SHAPE
+
+ * Thuban/UI/dialogs.py (NonModalDialog.__init__): The interactor
+ is gone. It's job from the dialog's point of view is now done by
+ the mainwindow, i.e. the parent.
+
+ * Thuban/UI/classifier.py (Classifier.__init__): The interactor is
+ gone. It's job from the dialog's point of view is now done by the
+ mainwindow, i.e. the parent.
+
+ * Thuban/UI/tree.py (SessionTreeView.__init__): The interactor is
+ gone. It's job from the dialog's point of view is now done by the
+ mainwindow, i.e. the parent.
+ (SessionTreeCtrl.__init__): New parameter mainwindow which is
+ stored as self.mainwindow. The mainwindow is need so that the tree
+ can still subscribe to the selection messages.
+ (SessionTreeCtrl.__init__, SessionTreeCtrl.unsubscribe_all)
+ (SessionTreeCtrl.update_tree, SessionTreeCtrl.OnSelChanged): The
+ selection is now accessible through the mainwindow. Subscribe to
+ SHAPES_SELECTED instead of SELECTED_SHAPE
+
+ * Thuban/UI/identifyview.py (IdentifyView.__init__): Use the
+ SHAPES_SELECTED message now.
+ (IdentifyView.selected_shape): Now subscribed to SHAPES_SELECTED,
+ so deal with multiple shapes
+ (IdentifyView.__init__, IdentifyView.OnClose): The interactor is
+ gone. It's job from the dialog's point of view is now done by the
+ mainwindow, i.e. the parent.
+
+ * Thuban/UI/controls.py (RecordListCtrl.fill_list): The second
+ parameter is now a list of shape ids.
+ (RecordTable.SetTable): The second parameter is now a list of
+ indices.
+
+ * Thuban/UI/renderer.py (ScreenRenderer.RenderMap): Rename the
+ selected_shape parameter and ivar to selected_shapes. It's now a
+ list of shape ids.
+ (MapRenderer.draw_label_layer): Deal with multiple selected
+ shapes. Rearrange the code a bit so that the setup and shape type
+ distinctions are only executed once.
+
+ * test/test_selection.py: Test cases for the selection class
+
+2003-03-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/load.py: Temporary fix so that the xml reader
+ doesn't cause Thuban to crash.
+
+ * Thuban/Model/layer.py: Handle the cyclic references between
+ a layer and its classification better, and be sure to disconnect
+ the classification from the layer when the layer is destroyed
+ so that we don't maintain a cyclic reference that may not be
+ garbage collected.
+
+ * Thuban/Model/classification.py: See comment for layer.py.
+
+2003-03-12 Jan-Oliver Wagner <jan at intevation.de>
+
+ * HOWTO-Release: New. Information on the steps for releasing
+ a new version of Thuban.
+
+2003-03-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py: Add normal border to SelectPropertiesDialog.
+ Use True instead of true.
+ (Classifier): Should have a single panel in which all the controls lie.
+
+ * Thuban/UI/proj4dialog.py: Add normal border.
+
+ * Thuban/UI/tree.py: Fixed problem with bad item images under Windows.
+
+ * Thuban/UI/mainwindow.py: Use True instead of true.
+
+ * setup.py: Update some definitions to use wxWindows2.4 files
+
+ * Data/iceland_sample_class.thuban: Fixed file so that the
+ field_type information is present.
+
+2003-03-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier.__init__): Make the
+ field type label grow so that when the text changes the
+ size is updated correctly. This may be a wxWindows bug.
+
+2003-03-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/application.py: Changed SESSION_CHANGED to
+ SESSION_REPLACED.
+
+ * Thuban/UI/classifier.py: Wrap text with _().
+ (ClassGrid.CreateTable): Set dimensions and size hints here,
+ instead of in Reset, so we only set the size once.
+
+ * Thuban/UI/dialogs.py: Don't need Shutdown(); just use Close()!
+
+ * Thuban/UI/mainwindow.py (MainWindow.prepare_new_session):
+ Call Close() instead of Shutdown().
+
+ * Thuban/UI/messages.py: Changed SESSION_CHANGED to SESSION_REPLACED.
+
+ * Thuban/UI/tree.py: Changed SESSION_CHANGED to SESSION_REPLACED.
+ Go back to using OnClose() instead of Shutdown().
+
+2003-03-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier): SelectField() needed
+ to know the old field index as well as the new one.
+
+2003-03-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier): Use __SelectField()
+ to correctly set the table information and call this from
+ __init__ and from _OnFieldSelect so that all the information
+ is up to date when the dialog opens and when a field is changed.
+
+2003-03-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py (Classification): Don't use
+ layer's message function directly, use the ClassChanged() method
+ when then classification changes. SetField/SetFieldType/SetLayer
+ must keep the information about field name and field type in
+ sync when an owning layer is set or removed.
+
+ * Thuban/Model/layer.py: Added ClassChanged() so that the
+ classification can tell the layer when its data has changed.
+ (Layer.SetClassification): Accepts None as an arguement to
+ remove the current classification and correctly handles
+ adding a new classification.
+
+ * Thuban/Model/load.py: Comment out print statement
+
+ * test/test_classification.py, test/test_save.py: New and
+ improved tests.
+
+2003-03-07 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Implemented __copy__ and
+ __deepcopy__ for ClassGroup* and ClassGroupProperites so
+ they can easily be copied by the classifier dialog.
+ (ClassGroupProperites.__init__): The default line color should
+ have been Color.Black.
+
+ * Thuban/UI/classifier.py: Setting and Getting table values now
+ uses a consistent set of functions.
+ (Classifier): Now non-modal. Has field type label which changes
+ as the field changes. Keep track of buttons in a list so that
+ we can enable/disable the buttons when the None field is selected.
+ (SelectPropertiesDialog): Add buttons to make the colors transparent.
+
+ * Thuban/UI/dialogs.py (NonModalDialog.Shutdown): New method which
+ does what OnClose did, but can be called by the application to
+ close a window. Needed when a session changes, and we have to
+ close the classifier windows.
+
+ * Thuban/UI/mainwindow.py (MainWindow.prepare_new_session):
+ Shuts down open dialogs. Used when a new session is created
+ or a session is opened.
+ (MainWindow.SaveSession): Should only call application.SaveSession()
+ if we don't call SaveSessionAs first.
+ (MainWindow.Classify): Allow different classifier dialogs for
+ different layers.
+
+ * Thuban/UI/tree.py (SessionTreeView): Remove OnClose and let
+ the parent class handle it. Add Shutdown() to unsubscibe from
+ event notification and call the parent Shutdown(). This was
+ necessary so the application can close the tree window.
+
+2003-03-06 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Minor documentation changes,
+ Addition of __eq__ and __ne__ methods.
+ (Classification.SetLayer): prevent recursion between this method
+ and Layer.SetClassification().
+
+ * Thuban/Model/color.py: Addition of __eq__ and __ne__ methods.
+
+ * Thuban/Model/layer.py (SetClassification): prevent recursion
+ between this method and Classification.SetLayer().
+
+ * test/test_classification.py, test/test_load.py,
+ test/test_session.py: Fixed and added tests for the classification
+ classes.
+
+2003-03-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/classifier.py (ClassGrid.__init__)
+ (ClassGrid.CreateTable): Move the SetSelectionMode call to
+ CreateTable because otherwise it triggers an assertion in
+ wxPython/wxGTK 2.4.
+
+2003-03-05 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/common.py: Move FIELDTYPE constants back to table.py.
+
+ * Thuban/Model/load.py: import FIELDTYPE constants from table.
+
+ * Thuban/UI/classifier.py: import FIELDTYPE constants from table.
+
+ * Thuban/Model/table.py: Put FIELDTYPE constants back.
+
+2003-03-05 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py: Added class documentation.
+ Fixed RTbug #1713, #1714. Added Move[Up|Down] buttons.
+ Store just the groups in the table and generate the other
+ column information when it is requested. Add "None" field
+ to pull-down to select no classification.
+
+ * Thuban/common.py: Moved FIELDTYPE constants from table.py
+ (Str2Num): Only catch ValueError exceptions.
+
+ * Thuban/Model/classification.py: Class documentation. Renaming
+ of methods with Stroke to Line. Groups are stored in a single
+ list with the default as the first element. Groups are searched
+ in the order they appear in the list.
+
+ * Thuban/Model/color.py: Documentation.
+
+ * Thuban/Model/layer.py (Layer): Add GetFieldType to retreive
+ the kind of data represented by a field.
+
+ * Thuban/Model/load.py (ProcessSession): Use proper string
+ conversion function; fixes RTbug #1713.
+
+ * Thuban/Model/save.py (Saver): Store field type information.
+
+ * Thuban/Model/table.py: Put FIELDTYPE constants in common.py.
+ (Table): Add field_info_by_name() to retrieve field information
+ by specifying the field name, not the number.
+
+ * Thuban/UI/mainwindow.py: Function name changes.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Only
+ get the layer classification once. Don't try to classify
+ values when the field is None: just use the default properties.
+
+ * Thuban/UI/view.py: Function name changes.
+
+ * Doc/thuban.dtd: Add field_type attribute to a classification.
+
+2003-03-04 Bernhard Herzog <bh at intevation.de>
+
+ * Doc/thuban.dtd: Use correct syntax for optional attributes. Make
+ the fill and stroke layer attributes optional with suitable
+ default values. Add the stroke_width layer attribute. Use correct
+ syntax for empty elements. Make the attribute list for labels
+ refer to the label element.
+
+2003-03-04 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (thuban_build_py.build): Add a comment about distutils in
+ Python 2.3 containing some of the functionality we implement in
+ setup.py ourselves.
+
+ * Thuban/UI/classifier.py (ClassGrid.__init__): Set the table
+ before the selection mode. Doing it the other way round triggers
+ an assertion in wxWindows.
+
+ * Thuban/Model/save.py (escape): Fix typo in doc-string
+
+ * Thuban/Model/classification.py: Remove unnecessary wxPython
+ import
+
+2003-03-04 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py (ClassGroupRange.GetProperties):
+ Parameter 'value' should default to None.
+
+ * Thuban/UI/mainwindow.py: Use Layer.GetClassification() since
+ the class attribute __classification is now private.
+
+ * Thuban/UI/classifier.py (ClassGrid): Moved OnCellDClick() from
+ Classifier to ClassGrid. Added support for removing selected rows,
+ which including code for keeping track of when cells are selected,
+ and deselected.
+ (ClassTable): Support for added/removing rows. Fixed a problem
+ with __ParseInput whereby it would not allow strings (only numbers)
+ to be entered.
+ (Classifier): Added button and supporting code for removing
+ selected rows.
+
+2003-02-27 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/common.py: Moved color conversion functions into
+ Thuban/UI/common.py.
+ (Str2Num): Now converts the float (not the string) to a long/int
+ so that an exception isn't thrown.
+
+ * Thuban/UI/common.py: Common functions used in several UI modules
+
+ * Thuban/Model/classification.py: Changed the class hierarchy
+ so that a Classification consists of Groups which return
+ Properties when a value matches a Group.
+
+ * Thuban/Model/layer.py: Fixed name resolution problem.
+
+ * Thuban/Model/load.py: Use new Classification and Group functions.
+
+ * Thuban/Model/save.py (Saver.write_attribs): Fixes a test case
+ failure.
+ (Saver.write_classification): Use new Classification and Group
+ functions.
+
+ * Thuban/UI/classifier.py: Changes to use new Classification and Group
+ functions. Fix to create a tuple with a single value instead of
+ simply returning the value.
+
+ * Thuban/UI/renderer.py: Use new Classification and Group functions.
+ Use common.py functions.
+
+ * Thuban/UI/tree.py: Use common.py functions.
+
+ * test/test_classification.py: Use new Classification and Group
+ classes.
+
+2003-02-24 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/common.py (Color2wxColour, wxColour2Color): Conversion
+ functions from Thuban color objects to wxWindow colour objects.
+
+ * Thuban/Model/classification.py (Classification): Renamed
+ GetProperties() to GetClassData(). Used the new iterator
+ in TreeInfo().
+ (ClassIterator): Iterator implementation to iterate over the
+ ClassData objects in a classification object.
+
+ * Thuban/Model/save.py (Saver.write_classificaton): Uses
+ the new iterator to save the classification information.
+
+ * Thuban/UI/classifier.py (SelectPropertiesDialog): Support
+ for changing the stroke and fill colors and previewing the
+ changes.
+
+ * Thuban/UI/mainwindow.py (MainWindow.OpenSession,
+ MainWindow.SaveSessionAs): Text string changes so the dialogs
+ have more meaningful titles.
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Change
+ Classification method name from GetProperties to GetClassData.
+
+ * Thuban/UI/view.py (MapCanvas.find_shape_at): Use method calls
+ instead of accessing now non-existent class variables.
+
+2003-02-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Remove
+ unneeded Shape() call. Rendering is substantially faster without
+ it and it avoids some problems with broken shape files.
+
+2003-02-20 Frank Koormann <frank at intevation.de>
+
+ Force minimal size of identify and label dialogs. The autosizing
+ looked too ugly.
+
+ * Thuban/UI/controls.py (RecordListCtrl): Set minimal width for columns.
+ * Thuban/UI/labeldialog.py (LabelDialog.dialog_layout):
+ Set size of listctrl.
+ * Thuban/UI/identifyview.py (IdentifyView.__init__):
+ Set size of dialog.
+
+2003-02-19 Jonathan Coles <jonathan at intevation.de>
+
+ * test/test_classification.py, test/test_layer.py,
+ test/test_load.py, test/test_map.py, test/test_session.py:
+ Updated the tests to use the new functions that are in the
+ respective classes.
+
+ * Thuban/Model/classification.py (Classification):
+ Uses the new ClassData* classes. Modification messages are
+ passed up to the parent layer (if it exists).
+ (ClassData): New class to encapsulate the common data in each
+ classification property.
+ (ClassDataDefault): Represents the Default class. data.
+ (ClassDataPoint): Represents a single class. data point
+ (ClassDataRange): Represents a class. range
+ (ClassDataMap): Represents a class. map (unused).
+
+ * Thuban/Model/color.py: Added Color.None to represent something
+ with no color. Color.Black represents the color black.
+ (NoColor): Helper class derived from Color to represent something
+ with no color.
+
+ * Thuban/Model/layer.py (Layer): Removed references to fill, stroke,
+ stroke_width attributes. Made the 'classification' attribute private.
+ New methods for setting/getting the classification.
+
+ * Thuban/Model/load.py (ProcessSession): Use new methods on Layer
+ to get the classifcation and use the new ClassData* classes to
+ hold the classification data. Use Str2Num to convert numbers
+ properly.
+
+ * Thuban/Model/save.py (Saver): Use new Color and Classification
+ methods
+
+ * Thuban/UI/classifier.py (ClassGrid): New class to represent a
+ custom grid.
+ (ClassTable): Support for editing Values and Labels and for
+ changing what type (point or range) of data is stored in each
+ property based on how the user enters the data.
+ (Classifier): Support for saving the new classifications and
+ launching the dialog to edit a property.
+ (SelectPropertiesDialog): New class for editing the visual
+ properties of a classification (stroke color, width, and fill color)
+ (ClassPreviewer): Took the Draw method from ClassRenderer and
+ made most of it into this new class. Intend to use this class in
+ the SelectPropertiesDialog for previewing changes.
+
+ * Thuban/UI/renderer.py: Use new Color and Classification methods.
+
+ * Thuban/UI/tree.py: Formatting changes.
+
+ * Doc/thuban.dtd: Add 'label' element
+
+ * Thuban/common.py: New. Contains common routines used throughout
+ the code.
+ (Str2Num): Takes a string and converts it to the "best" type of
+ number.
+
+2003-02-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.OnLeftUp): Make sure that the
+ dragging flag is always set to 0 even when the tool implementation
+ raises an exception
+
+2003-02-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.splash_screen): New
+ method to create a splash screen.
+ (ThubanApplication.ShowMainWindow): New. Show the main window.
+ Needed so the splash screen can display the mainwindow
+ (ThubanApplication.OnInit): Call the
+ new splash_screen method to determine whether the application
+ should display a splash screen. If it displays a splash screen do
+ not immediately show the main window.
+
+2003-02-11 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py: Added import line to fix
+ feature conflicts between running on python2.2 and python2.1.
+
+ * Thuban/UI/classifier.py (ClassTable): Didn't need to hang
+ onto the clinfo parameter, so removed the deepcopy().
+
+2003-02-10 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/save.py (Saver.open_element, Saver.close_element):
+ Added element_open variable to track opening and closing of tags
+ so that tags that don't span more than one line are closed with
+ /> instead of </tag_name>. Use the GetDefault*() methods of
+ the Classification class.
+
+ * Thuban/Model/classification.py (Classificaton): Added set and
+ get methods for the default data. The class also takes a layer
+ reference so that modification messages can be sent. Fixed the
+ methods to use the new ClassData class.
+ (ClassData): New class to encapsulate the classification data
+
+ * Thuban/Model/layer.py (Layer): Remove the
+ Set[Fill|Stroke|StrokeWidth]() methods. Code should call the
+ SetDefault*() methods on the layer's classification object.
+ (Layer.__init__): Use the new SetDefault*() methods in the
+ Classification class.
+
+ * Thuban/Model/load.py (ProcessSession): Use the new ClassData
+ object instead of a dictionary.
+
+ * Thuban/UI/classifier.py (ClassRenderer): New class to
+ draw the classifications in the dialog box's table.
+ (Classifier): Modified to use the ClassRenderer class.
+
+ * Thuban/UI/mainwindow.py (MainWindow): Use the SetDefault*()
+ methods of the Classification class.
+
+ * Thuban/UI/renderer.py (MapRenderer): Use the Get*() methods
+ of the ClassData class.
+
+ * test/test_classification.py, test/test_layer.py,
+ test/test_map.py, test/test_session.py: Fix the tests to work
+ with the above code changes.
+
+2003-02-03 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/classification.py (Classification): Added getNull()
+ to return the NullData reference
+
+ * Thuban/Model/layer.py (Layer.SetFill, Layer.SetStroke,
+ Layer.SetStrokeWidth): Modified these functions to change the
+ null data in the classification rather than keep these values
+ directly in the Layer class. Menu options to change these values
+ work again.
+
+2003-01-28 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/UI/classifier.py (Classifier): Resolved merging conflicts.
+ Fixed crashing problem on some systems. Dialog box shows
+ classification data.
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.add_items): Handle drawing
+ Colors in the tree view.
+
+ * Thuban/Model/layer.py (Layer.TreeInfo): Added a call to build
+ the tree info for classifications. Commented out unnecessary lines.
+
+ * Thuban/Model/classification.py (Classification.TreeInfo): New
+ function to add information about the classification into the
+ tree view.
+
+2003-01-27 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/__init__.py (_): New.
+
+ * Thuban/Model/classification.py, Thuban/Model/extension.py,
+ Thuban/Model/layer.py, Thuban/Model/load.py, Thuban/Model/map.py,
+ Thuban/Model/session.py, Thuban/UI/application.py,
+ Thuban/UI/classifier.py, Thuban/UI/context.py, Thuban/UI/controls.py,
+ Thuban/UI/identifyview.py, Thuban/UI/labeldialog.py,
+ Thuban/UI/mainwindow.py, Thuban/UI/menu.py, Thuban/UI/proj4dialog.py,
+ Thuban/UI/renderer.py, Thuban/UI/tree.py, Thuban/Lib/connector.py,
+ Thuban/Lib/fileutil.py: Replace user string by _() for i18n.
+
+2003-01-27 Jonathan Coles <jonathan at intevation.de>
+
+ * Thuban/Model/layer.py: Classification initialization calls.
+
+ * Thuban/Model/classification.py: Created class to encapsulate
+ a layer classification. Supports specific data points and
+ ranges.
+
+ * Thuban/Model/load.py: Added support for loading classification
+ information.
+
+ * Thuban/Model/save.py: Added support for saving classification
+ information.
+
+ * Thuban/UI/classifier.py: Initial class for a dialog box for
+ specifying classification information.
+
+ * Thuban/UI/mainwindows.py: Support for opening the classifier
+ dialog.
+
+ * Thuban/UI/renderer.py: Support for drawing a layer with the
+ classification information.
+
+ * Data/iceland_sample_class.thuban: iceland_sample with
+ classification data.
+
+ * test/test_classification: Tests for the Classification class.
+
+2002-12-09 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_command.py: New. Tests for the command classes.
+
+ * Thuban/UI/command.py (ToolCommand): New class for tool commands.
+ (Command.IsTool): New method to distinguish between command
+ switching tools and other commands.
+
+ * Thuban/UI/view.py (MapCanvas.SelectTool): New method to select
+ the tool to avoid direct assignments to instance variables
+ (MapCanvas.ZoomInTool, MapCanvas.ZoomOutTool, MapCanvas.PanTool)
+ (MapCanvas.IdentifyTool, MapCanvas.LabelTool): Use SelectTool to
+ change the tool
+
+ * Thuban/UI/mainwindow.py (MainWindow.update_command_ui): If an
+ active tool's command turns insensitive, disable the tool.
+ (_tool_command): Use the new ToolCommand class
+
+ * Examples/simple_extensions/simple_tool.py (simple_tool): Use the
+ SelectTool method to change the tool
+ (iconfile): Use the ToolCommand class
+
+2002-12-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.normalize_selection): Handle
+ the case of selected items that are not children of Layers or Maps
+ properly. Previously this bug would trigger an assertion in
+ wxWindows.
+
+2002-11-06 Frank Koormann <franmk.koormann at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Altered the order of tools in the
+ toolbar: First now are all navigation tools (Zoom In/Out, Pan,
+ Full Extent).
+
+2002-10-23 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (setup call): version now 0.1.3
+
+ * MANIFEST.in: Add the files in test/
+
+ * test/README: Add note about tests requiring the iceland data
+
+ * Thuban/UI/mainwindow.py (MainWindow.About): Add 2002 to
+ copyright notice.
+
+2002-10-18 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_map.py
+ (TestMapWithContents.test_projected_bounding_box): Use an explicit
+ epsilon.
+
+ * test/support.py (FloatComparisonMixin.assertFloatEqual)
+ (FloatComparisonMixin.assertFloatSeqEqual): give a more useful
+ message if the assertion fails and don't return the return value
+ of self.assert_. In assertFloatSeqEqual the return meant that not
+ all items of the sequence were compared.
+
+2002-09-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_fileutil.py: New. Test cases for Thuban.Lib.fileutil
+
+ * Thuban/Lib/fileutil.py: Fixup some whitespace and typos
+
+ * test/test_map.py (TestMapWithContents.test_tree_info): Create
+ the string with the bounding box on the fly because of platform
+ differences in the way %g is handled.
+
+ * test/test_layer.py (TestLayer.test_empty_layer): Create an empty
+ DBFfile too because Thuban layers can't yet cope missing DBF
+ files.
+
+2002-09-20 Bernhard Herzog <bh at intevation.de>
+
+ * test/test_menu.py: Use initthuban instead of
+ add_thuban_dir_to_path to initialize Thuban.
+
+ * test/support.py (FloatComparisonMixin.assertFloatEqual): New.
+ Mixin class for float comparisons
+ (SubscriberMixin): New. Mixin class to test messages sent through
+ the Connector class
+
+ * test/README: Fix a typo and add the -v flag to the command for
+ individual tests
+
+ * test/test_session.py: New. Test cases for Thuban.Model.session
+
+ * test/test_proj.py: New. Test cases for Thuban.Model.proj
+
+ * test/test_map.py: New. Test cases for Thuban.Model.map
+
+ * test/test_layer.py: New. Test cases for Thuban.Model.layer
+
+ * test/test_label.py: New. Test cases for Thuban.Model.label
+
+ * test/test_connector.py: New. Test cases for Thuban.Lib.connector
+
+ * test/test_color.py: New. Test cases for Thuban.Model.color
+
+ * test/test_base.py: New. Test cases for Thuban.Model.base
+
+2002-09-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py (Session.forwarded_channels): Forward
+ the CHANGED channel too.
+
+ * Thuban/Model/map.py (Map.forwarded_channels): Forward the
+ CHANGED channel too.
+ (Map.__init__): Call the Modifiable constructor as well.
+
+ * Thuban/Model/base.py (Modifiable.UnsetModified): Issue a CHANGED
+ event if the modified flag changes.
+ (Modifiable.changed): Tweak the doc-string.
+
+ * Thuban/UI/mainwindow.py (MainWindow.view_position_changed)
+ (MainWindow.set_position_text): Put the code that puts the text
+ with the mouse position into the status bar into the new method
+ set_position_text so that it can overwritten in derived classes.
+
+2002-09-12 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.RunMessageBox): Center the
+ message box on the main window.
+
+2002-09-11 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Underline the 'x' in "Exit" instead of
+ the 'E' because it's less likely to interfere with other menu
+ entries.
+ (MainWindow.build_menu): remove an incorrect comment.
+
+2002-09-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.Map): New.
+ (_tool_command): Add sensitive parameter
+ (_has_visible_map): Sensitivity callback to tools and other
+ commands that require a visible map. Use it in map_zoom_in_tool,
+ map_zoom_out_tool, map_pan_tool, map_identify_tool, map_label_tool
+ and map_full_extent
+
+2002-09-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.OnClose): Unsubscribe
+ VIEW_POSITION
+
+2002-09-04 Frank Koormann <frank.koormann at intevation.de>
+
+ * Resources/Bitmaps/fullextent.xpm: Updated Icon (removed "potatoe")
+
+2002-09-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py: Get rid of the idle redraw. This is done by
+ wxWindows already and our implementation doesn't work correctly
+ with wxGTK 2.3:
+ (MapCanvas.__init__): Remove the instance variable
+ (MapCanvas.OnPaint): Always call do_redraw when there's a map to
+ be drawin
+ (MapCanvas.OnIdle): Removed.
+
+ * Thuban/UI/view.py (MapCanvas.unprojected_rect_around_point): Add
+ a parameter to determine the size of the rectangle.
+ (MapCanvas.find_shape_at): Create the box around the point on a
+ layer by layer basis and make the size depend on the shape type.
+ This solves a problem with the selection of point shapes at the
+ border of the layer's bounding box
+
+2002-08-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.CanRemoveLayer): New method
+ for the sensitivity of remove layer.
+ (_can_remove_layer): New. Sensitivity callback for remove layer
+ (Command layer_remove): Use _can_remove_layer
+
+ * Thuban/Model/map.py (Map.CanRemoveLayer): New method to
+ determine whether a given layer can be deleted.
+
+ * Thuban/UI/view.py (MapCanvas.__init__, MapCanvas.OnPaint)
+ (MapCanvas.do_redraw): Get rid of the unused update_region
+ instance variable
+
+ * Thuban/UI/view.py: Add/update some doc-strings.
+
+ * test/: new subdirectory with a bunch of unit tests.
+
+ * test/README, test/test_table.py, test/test_save.py,
+ test/test_menu.py, test/test_load.py: Initial set of tests and
+ brief instructions on how to run them
+
+2002-08-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/renderer.py (ScreenRenderer.draw_shape_layer): Handle
+ arcs with multiple parts.
+
+ * Thuban/UI/view.py (ZoomInTool.MouseUp, ZoomOutTool.MouseUp):
+ Handle degenrate rectangles.
+
+ * Thuban/Model/table.py: Make writing records work correctly:
+ (Table.__init__): Keep track of whether the DBF is open for
+ writing
+ (Table.write_record): Open the DBF file for writing when necessary
+
+2002-08-27 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (Table.write_record, Table.__init__): Open
+ dbf files only for reading by default. Use a new writable dbf
+ object for writing.
+
+2002-08-26 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py: Refactor the context creation:
+ (MainWindow.Context): New method to return a context
+ (MainWindow.invoke_command, MainWindow.update_command_ui): Use the
+ new method
+
+ * Thuban/UI/tableview.py (TableGrid, LayerTableGrid): Split the
+ layer table specific code from TableGrid into LayerTableGrid
+ (TableFrame, LayerTableFrame): Split the layer table specific code
+ from TableFrame into LayerTableFrame
+ (LayerTableGrid.select_shape): Remove a debug print
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Use the
+ LayerTableFrame
+
+2002-08-23 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.__init__): Make sure we have an
+ absolute filename.
+
+2002-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/table.py (Table.write_record): New method to write
+ records.
+ (Table.__init__): Open the DBF file for writing too.
+
+ * Thuban/UI/controls.py (RecordTable.SetValue): Write the value
+ into the underlying table.
+
+ * extensions/shapelib/shapefil.h (DBFCommit),
+ extensions/shapelib/dbfopen.c (DBFCommit): New API function to
+ commit any changes made to the DBF file.
+
+ * Thuban/UI/mainwindow.py (make_check_current_tool)
+ (_tool_command): Put the code that generates the "checked"
+ callback into a separate function so that we can reuse it
+ elsewhere
+
+ * Thuban/Model/save.py (Saver): New class to handle serializing a
+ session into an XML file. The main reason to introduce a class is
+ that applications built on Thuban can derive from it so that they
+ can save additional information in a session file.
+ (save_session): Delegate almost all the work to the Saver class.
+ Rename the filename argument to file because it may be a file like
+ object now.
+
+ * Thuban/Model/load.py: Get rid of the Python 1.5.2 compatibility
+ code. Remove the little test code which would be executed when the
+ module is run as a script which didn't work anymore since it can't
+ import the other Thuban modules.
+ (ProcessSession, load_session): Refactor the ProcessSession to
+ have one method for each element start and end tag so that derived
+ classes can easily override the processing of individual tags.
+ Also, always parse with namespaces enabled because applications
+ built on top of Thuban will likely use namespaces if they extend
+ the session file format.
+
+2002-08-21 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (ThubanInstall.run): Don't repr install_lib_orig
+ because thubaninit_contents will do it for us.
+
+2002-08-16 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py: menu item 'show session tree' now disable if
+ tree window already open
+
+2002-08-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.Destroy): Call the unboundd method
+ with self.
+
+ * Thuban/UI/view.py (MapCanvas.OnLeftUp): Only release the mouse
+ when we have actually captured it.
+
+ * Thuban/Model/layer.py (Layer.Destroy): New. Explicitly close the
+ shapefile and destroy the table.
+
+ * Thuban/Model/table.py (Table.Destroy): New. Close the DBF file.
+
+2002-08-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/controls.py (RecordTable.__init__): Remove the unused
+ instance variable columns
+ (RecordTable.GetTypeName): row and col may be negative in some
+ cases.
+
+ * setup.py (InstallLocal.initialize_options)
+ (InstallLocal.finalize_options, InstallLocal.user_options): New
+ option create-init-file to build a thubaninit.py when running
+ install_local
+ (InstallLocal.run): Create the thubaninit.py module when requested
+ (thubaninit_contents): Split the template into several parts and
+ create a new function thubaninit_contents that creates the
+ contents of a thubaninit module.
+ (ThubanInstall.run): Use the new function to create the thubaninit
+ module.
+
+2002-07-30 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.OnExit): Do some
+ cleanup.
+ (ThubanApplication.MainLoop): Extend to automatically call OnExit.
+
+ * Thuban/Model/session.py (Session.Destroy): Don't bypass the
+ direct base class' Destroy method.
+
+ * Thuban/Model/map.py (Map.ClearLayers): New method to delete all
+ layers.
+ (Map.Destroy): Destroy the label_layer as well and call the
+ inherited Desatroymethod first so that no more messages are
+ issued.
+ (Map.RaiseLayer, Map.LowerLayer): Only issue LAYERS_CHANGED
+ message if the stacking order actually has changed. Add
+ doc-strings.
+ (Map.BoundingBox): Correct the doc-string.
+ (Map.AddLayer, Map.RemoveLayer, Map.Layers, Map.HasLayers)
+ (Map.ProjectedBoundingBox, Map.SetProjection): Add doc-strings.
+
+ * Thuban/Model/label.py (LabelLayer.ClearLabels): New to delete
+ all labels.
+
+2002-07-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/map.py (Map.subscribe_layer_channels)
+ (Map.unsubscribe_layer_channels): Put the code that (un)subscribes
+ to a layer's channels into separate methods.
+ (Map.RemoveLayer, Map.AddLayer): Call the new methods
+ (Map.Destroy): Unsubscribe from a layer's channels before
+ destroying it.
+
+ * Thuban/UI/view.py (MapCanvas.find_shape_at): Change the
+ selected_layer parameter to searched_layer which is the layer to
+ search in.
+ (MapCanvas.SelectShapeAt): New parameter layer to restrict the
+ search to that layer. Return the selected layer and shape.
+
+ * Examples/simple_extensions/simple_tool.py (simple_tool): Fix a
+ typo
+
+2002-07-24 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py (ThubanApplication.create_session):
+ Extend the doc string.
+ (ThubanApplication.subscribe_session)
+ (ThubanApplication.unsubscribe_session): New methods to
+ subscribe/unsubscribe to/from session channels.
+ (ThubanApplication.SetSession): Call the new methods here.
+ (ThubanApplication.maps_changed, ThubanApplication.set_map):
+ Renamed set_map to maps_changed. Its now a subscriber for
+ MAPS_CHANGED.
+
+ * Thuban/UI/view.py (ZoomOutTool.MouseUp): Use the correct
+ x-coordinate in case of simple clicks
+
+ * Thuban/Model/base.py (Modifiable.changed): Apply the args tuple,
+ don't pass it as a parameter
+
+ * Thuban/Model/session.py (Session.RemoveMap): New
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Turn the initial
+ window size into a parameter.
+
+2002-07-23 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/menu.py (Menu.item_index): Also search for menus not
+ just commands.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Change the
+ parameter list a bit to allow setting the window title and the
+ initial message in the status bar. Update the callers.
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit)
+ (ThubanApplication.CreateMainWindow): Put the mainwindow
+ instantiation into a separate method so that it can be overridden
+ by a subclass.
+
+2002-07-19 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/session.py: Issue a CHANGED message every time
+ another changed message is issued to make it easier to get
+ notified of changes.
+ (Session): Update the doc string
+ (Session.forward): Issue changed-events as CHANGED as well.
+ (Session.changed): Overwrite the inherited version to issue
+ CHANGED events as well.
+
+ * Thuban/UI/tree.py: We can now simply subscribe to the session's
+ CHANGED channel to be informed of changes.
+ (SessionTreeCtrl.session_channels): Not needed any longer.
+ (SessionTreeCtrl.unsubscribe_all, SessionTreeCtrl.session_changed):
+ Only have to (un)subscribe CHANGED
+
+ * Thuban/Model/map.py (Map.TreeInfo): Deal better with empty maps.
+
+ * Thuban/UI/main.py, Thuban/UI/__init__.py: Move the work-around
+ for the wxPython locale bug to __init__.py so that it's
+ automatically executed by anybody using UI code from Thuban.
+
+2002-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/main.py (main): app no longer needs to be global
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Add application
+ as parameter and store it in an instance variable
+ (MainWindow.invoke_command, MainWindow.update_command_ui)
+ (MainWindow.save_modified_session, MainWindow.NewSession)
+ (MainWindow.OpenSession, MainWindow.SaveSession)
+ (MainWindow.SaveSessionAs, MainWindow.ShowSessionTree): Use self's
+ application object.
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Instantiate
+ the main window with self.
+
+ * Thuban/UI/context.py: New module with the context class
+
+ * Thuban/UI/command.py (Command): Update doc string.
+
+ * Thuban/UI/mainwindow.py (MainWindow.invoke_command,
+ MainWindow.update_command_ui): Pass an instance of the context
+ class to the command's methods
+ (check_current_tool, call_method): Handle the new context
+ implementation
+
+ * Examples/simple_extensions/simple_tool.py (simple_tool,
+ check_simple_tool): Handle the new context implementation
+
+ * Examples/simple_extensions/simple_command.py (simple_command):
+ Handle the new context implementation. Update the comments about
+ the context.
+
+ * Thuban/UI/application.py (ThubanApplication.SetSession): Add
+ doc-string
+ (ThubanApplication.Session): New method to return the session
+ object
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.update_tree): The
+ interactor's selected_layer may not be a layer of the current
+ session when the tree is updated while a new session is being set.
+
+2002-07-17 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tree.py (color_string): Removed. No longer used.
+ (SessionTreeCtrl.update_tree, SessionTreeCtrl.add_items): Split
+ update_tree into update_tree and add_items. The tree now uses a
+ more generic way to display the contents of the tree.
+ (SessionTreeCtrl): Add a doc string explaining the TreeInfo method
+
+ * Thuban/Model/layer.py (Layer.TreeInfo),
+ Thuban/Model/extension.py (Extension.TreeInfo),
+ Thuban/Model/map.py (Map.TreeInfo),
+ Thuban/Model/session.py (Session.TreeInfo):
+ Add TreeInfo methods to implement the new tree view update scheme
+
+2002-07-16 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/application.py: Don't use "import from" for the
+ MainWindow. It can't always be resolved.
+ (ThubanApplication.OnInit): change reference to MainWindow
+ accordingly.
+
+ * Thuban/UI/menu.py (Menu.SetItems): New method to replace a menu
+ completely
+
+2002-07-10 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (create_init_module): New configurable variable whose
+ default depends on the platform we're running on.
+ (ThubanInstall.initialize_options): Initialize
+ self.create_init_module from the global create_init_module
+ (ThubanInstall.user_options): indictate that the options
+ create-init-module and init-module-dir have arguments.
+
+ * setup.py: In the setup call change the version number to include
+ cvs.
+
+ * MANIFEST.in: Add the files in Examples
+
+2002-07-09 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: In the setup call, use the thuban homepage as the
+ value of the url parameter.
+
+ * Examples: New subdirectory for examples.
+
+ * Examples/simple_extensions/simple_tool.xpm,
+ Examples/simple_extensions/simple_tool.py,
+ Examples/simple_extensions/simple_command.py,
+ Examples/simple_extensions/README: Simple examples showing how to
+ add new commands and tools.
+
+ * setup.cfg (bdist_rpm): Add the default value for prefix and tell
+ bdist_rpm that we also have an install script.
+ (bdist_inno): Add 2002 to the copyright notice.
+
+ * setup.py: Create a file in python's site-packages directory to
+ make installation of Thuban as a library easier.
+ (ThubanInstall.user_options): Add two new options,
+ create-init-module and init-module-dir
+ (ThubanInstall.expand_with_pure_python_dirs): New method to expand
+ filenames for installation in the default directories.
+ (ThubanInstall.select_scheme, ThubanInstall.convert_paths): Extend
+ the inherited methods to capture some filenames before they're
+ transformed too much by distutils.
+ (ThubanInstall.run): Create the init module if requested.
+ (ThubanInstall.thuban_init_filename): New method to return the
+ full name of the init module.
+ (ThubanInstall.get_outputs): Append the filename of the init
+ module.
+
+2002-07-08 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (thuban_bdist_rpm): Extend this version of bdist_rpm to
+ handle the prefix properly which means that the default for the
+ installation prefix should be /usr for RPMs and /usr/local when
+ doing a normal source install.
+ (bdist_rpm_install_script): Script to override the default install
+ commands in the specfile generated by the bdist_rpm command.
+ (thuban_bdist_rpm.user_options): Add a prefix option
+ (thuban_bdist_rpm.initialize_options): Init the prefix option.
+ Create the script files for the spec files as empty files here
+ (thuban_bdist_rpm._make_spec_file): Override the inherited method
+ to fill the script files with content.
+
+ * Thuban/Model/save.py (relative_filename): Wrapper around
+ Thuban.Lib.fileutil.relative_filename that accepts an empty dir
+ argument. save_session now automatically uses this version,
+ solving a problem when saving to a relative filename.
+
+ * setup.py: In the setup call, make sure that the library
+ directories are under $prefix/lib not directly under $prefix.
+
+2002-06-20 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/Model/extension.py: new module to handle extension objects.
+ * Thuban/Model/messages.py: new messages for extensions.
+ * Thuban/Model/session.py (Session.Extensions, Session.HasExtensions,
+ Session.AddExtension): new for handling extensions.
+ Also some other minor changes to round up extension handling.
+ * Thuban/UI/tree.py (SessionTreeCrtl:update_tree): Added visualization
+ of Extension titles and title and names of its objects.
+
+2002-05-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.bind_command_events): Bind
+ the events for a command.
+ (MainWindow.add_toolbar_command, MainWindow.add_menu_command):
+ Call bind_command_events to bind the events. add_toolbar_command
+ can now bind events too so that it's possible to have commands
+ that are only available through the toolbar.
+ (MainWindow.init_ids): New instance variable events_bound to keep
+ track of for which commands events have been bound.
+
+2002-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/menu.py: New module to build and manage menus.
+
+ * Thuban/UI/mainwindow.py: Remove some unused imports.
+ (MainWindow.__init__, main_menu): move the definition of the main
+ menu from __init__ to the Menu instance main_menu.
+ (MainWindow.build_menu_bar, MainWindow.build_menu): New methods to
+ build the menu bar and sub-menus from a menu description.
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Read the
+ startup file
+ (ThubanApplication.read_startup_files): New method to run
+ ~/.thuban/thubanstart.py
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__, main_toolbar):
+ Move the toolbar definition to the Menu instance main_toolbar.
+ (MainWindow.build_toolbar): New method to build the toolbar
+ similar to the build_menu methods
+
+2002-05-23 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Fix spelling of
+ layer_outline_color. Fix it in the definition of the command too.
+
+ * Thuban/UI/command.py (Command): Fix typo in doc string
+
+2002-05-22 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.RunMessageBox): Fix a typo
+ in the docstring
+
+2002-05-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.open_shapefile): Set bbox to None
+ when the shapefile is empty.
+ (Layer.BoundingBox, Layer.LatLongBoundingBox): Both methods may
+ now return None for empty shapefiles. Update doc-strings.
+
+ * Thuban/Model/map.py (Map.BoundingBox): Add doc-string. Deal with
+ the layer's bbox being None.
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.update_tree): Deal with the
+ layer's bbox being None.
+
+ * Thuban/UI/view.py (MapCanvas.shape_selected): Only redraw when
+ necessary.
+ (MapCanvas.__init__): New instance variables, last_selected_layer
+ and last_selected_shape to determine how the selection has
+ changed.
+
+ * Thuban/UI/tableview.py (TableGrid.__init__): Do not call
+ AutoSizeColumns because it will cause a traversal of the entire
+ table which for large .dbf files will take a very long time.
+
+2002-05-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.open_shapefile): Choose a better
+ maximum depth for the tree than shapelib does by default.
+
+2002-05-10 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (py_modules): The shptree modules doesn't have a
+ wrapper, so don't include it in the py_modules
+
+2002-05-08 Bernhard Herzog <bh at intevation.de>
+
+ * extensions/shapelib/shptree.c (compare_ints): Make arguments
+ const void * as in the qsort prototype
+ (SHPTreeFindLikelyShapes): Remove some unused variables.
+
+ * Thuban/UI/view.py (PanTool.MouseMove): Use the bitmap the view
+ maintains to redraw the window during a drag.
+ (MapCanvas.unprojected_rect_around_point): New method to determine
+ a small region around a point for hit-testing.
+ (MapCanvas.find_shape_at): Only test the shapes in a small region
+ around the point.
+
+ * setup.py: Increment the version to 0.1.2
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.unsubscribe_all): Remove a
+ debug print and set session to None after unsubscribing
+
+2002-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * Data/iceland_sample.session, Data/iceland_sample.thuban: Rename
+ the file to have a .thuban extension.
+
+ * Thuban/UI/tree.py (session_channels): New class constant with
+ all the session channels to subscribe to to update the tree
+ (SessionTreeCtrl.session_changed): Remember the session so that we
+ can unsubscribe properly. Use the new class constant to
+ unsubscribe from the old session and subscribe to the new one.
+ (SessionTreeCtrl.unsubscribe_all): New method to unsubscribe all
+ subscriptions of the SessionTreeCtrl.
+ (SessionTreeView.OnClose): Call the tree's unsubscribe_all method.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Add the "Show
+ Session Tree" command to the file menu.
+
+ * Thuban/UI/view.py (MapCanvas.do_redraw): Pass the entire bitmap
+ as update_region to the renderer.
+
+ * Thuban/UI/renderer.py
+ (ScreenRenderer.layer_ids, ScreenRenderer.draw_shape_layer): The
+ update box is now directly a tuple, not a wxRect anymore.
+
+ * Thuban/Model/layer.py (Layer.ShapesInRegion): Remove some debug
+ prints.
+
+2002-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: Add the shptree extension module. See
+ extensions/pyshapelib/ChangeLog for more details.
+
+ * extensions/shapelib/shpopen.c, extensions/shapelib/shapefil.h,
+ extensions/shapelib/dbfopen.c: Really update to the versions of
+ shapelib 1.2.9. For some reason it wasn't really done on
+ 2002-04-11.
+
+ * extensions/shapelib/shptree.c: Modified version of shptree.c of
+ shapelib 1.2.9. The only real difference is the use of qsort
+ instead of a bubble sort implementation
+
+ * Thuban/Model/layer.py (Layer.__init__): New instance variable
+ shapetree to hold the shapelib quadtree for the shapefile
+ (Layer.open_shapefile): Create the quad tree.
+ (Layer.ShapesInRegion): New method to return the ids of shapes in
+ a given region using the quad tree.
+
+ * extensions/thuban/wxproj.cpp (project_points): Fix some typos in
+ comment
+ (draw_polygon_shape): Accept both arcs and polygons.
+ (initwxproj): Use the new PYSHAPELIB_IMPORT_API macro to import
+ the api.
+
+ * Thuban/UI/renderer.py (MapRenderer.layer_ids): New method to
+ return the shape ids to be rendered in a given layer.
+ (MapRenderer.draw_shape_layer): Call layer_ids to get the list of
+ ids. Use draw_polygon_shape to draw arc shapes as well.
+ (ScreenRenderer.RenderMap): New parameter for the rectangle that
+ has to be updated
+ (ScreenRenderer.layer_ids): Make use of the layer's quadtree by
+ calling it's ShapesInRegion method.
+
+ * Thuban/UI/view.py (MapCanvas.__init__): New instance variable
+ update_region for the update region.
+ (MapCanvas.OnPaint): Maintain the update region
+ (MapCanvas.do_redraw): Pass the bounding box of the update_region
+ to the renderer when drawing the bitmap. Reset the update_region.
+
+2002-05-03 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.SaveSessionAs,
+ MainWindow.OpenSession): Change the file extension of the session
+ files to .thuban
+
+ * Thuban/Model/session.py (Session.AddMap, forwarded_channels):
+ Move the map channels to be forwarded by the session into the
+ class constant with forwarded_channels. Also add
+ LAYER_PROJECTION_CHANGED and LAYER_VISIBILITY_CHANGED to
+ forwarded_channels
+
+ * Thuban/Model/base.py (Modifiable.changed): Fix doc-string (a
+ typo and some rewording).
+
+2002-05-02 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py: Keep the temporary bitmap used during drawing
+ around to speed up most redraws:
+ (MapCanvas.__init__): New instance variable bitmap which holds the
+ bitmap
+ (MapCanvas.do_redraw): Redraw self.bitmap if necessary. Use
+ self.bitmap to draw.
+ (MapCanvas.full_redraw): New method to force a full redraw
+ including the bitmap
+ (MapCanvas.SetMap): Subscribe full_redraw instead of redraw to
+ make sure the bitmap is redrawn.
+ (MapCanvas.projection_changed, MapCanvas.set_view_transform,
+ MapCanvas.shape_selected): Call full_redraw instead of readraw to
+ make sure the bitmap is redrawn.
+ (MapCanvas.OnSize): New method to handle size events so that the
+ bitmap can be redrawn.
+
+2002-04-29 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Subscribe to the
+ canvas' VIEW_POSITION event
+ (MainWindow.view_position_changed): Handler for VIEW_POSITION.
+ Update the text in the status-bar accordingly.
+
+ * Thuban/UI/view.py (MapCanvas): Derive from Publisher as well
+ (MapCanvas.__del__): Implement because Publisher.__del__ has to be
+ called.
+ (MapCanvas.__init__): Bind EVT_LEAVE_WINDOW too. Initialize
+ current_position
+ (MapCanvas.set_current_position): New method to set
+ current_position. Issue a VIEW_POSITION event
+ (MapCanvas.CurrentPosition): New public method to return the value
+ of current_position. Should be called when the VIEW_POSITION event
+ is processed.
+ (MapCanvas.OnLeftDown, MapCanvas.OnLeftUp, MapCanvas.OnMotion):
+ Update the position.
+ (MapCanvas.OnLeaveWindow): Set the position to None.
+
+ * Thuban/UI/messages.py (VIEW_POSITION): New message for the
+ position in the statusbar
+
+2002-04-26 Frank Koormann <frank at intevation.de>
+
+ * Thuban/UI/mainwindow.py: AddLayer, Dialog title s/session/data
+
+2002-04-24 Frank Koormann <frank at intevation.de>
+
+ * Resources/Bitmaps/identify.xpm: shadow added
+
+ * Resources/Bitmaps/fullextent.xpm: new
+
+2002-04-22 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/tree.py (update_tree): added test for None on map bounding
+ box
+
+2002-04-21 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/proj4dialog.py (UTMProposeZoneDialog): new
+
+ * Thuban/UI/tree.py (update_tree): added added map extent
+
+ * Thuban/UI/mainwindow.py (_method_command): extended by parameter
+ icon; added map_full_extend as tool
+
+2002-04-19 Jan-Oliver Wagner <jan at intevation.de>
+
+ * Thuban/UI/mainwindow.py (SaveSession): launch save as dialog for
+ saving _new_ sessions
+
+ * Thuban/Model/session.py (create_empty_session): new session
+ don't have a filename (set to None)
+
+ * Thuban/UI/tree.py (update_tree): added filename and modified flag
+
+ * Thuban/Model/load.py (ProcessSession): convert projection
+ parameters from unicode to regular string
+
+ * Data/iceland_sample.session: Added UTM Zone 26 projection.
+
+2002-04-11 Bernhard Herzog <bh at intevation.de>
+
+ * extensions/shapelib/shapefil.h, extensions/shapelib/shpopen.c,
+ extensions/shapelib/dbfopen.c: Update to the versions of shapelib
+ 1.2.9
+
+ * setup.py (Lib.wxproj extension): Don't link shpopen.c and put
+ the pyshapelib directoy into the list of include dirs, so that
+ pyshapelib_api.h can be found.
+
+ * extensions/thuban/wxproj.cpp (pyshapelib_api): New variable that
+ holds the pyshapelib C-API
+ (draw_polygon_shape, point_in_polygon_shape, shape_centroid): Use
+ pyshapelib_api to access the shapelib functions.
+ (initwxproj): Import the c_api from the shapelib module and
+ initialize pyshapelib_api.
+
+2002-04-04 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (thuban_bdist_rpm.initialize_options): Use
+ initialize_options to create the scripts for the rpm.
+
+ * extensions/pyprojection/setup.py (PROJ4_PREFIX): Just use /
+
+2002-04-03 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: Increment version to 0.1.1
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Move the "Add
+ Layer" and "Remove Layer" commands from the layer menu to the map
+ menu
+
+2002-02-15 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/Model/layer.py (Layer.Shape): list append only takes one
+ argument (python <= 1.5.2 erroneously accepted multiuple
+ arguments)
+
+2002-02-04 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyGridCtrl): New class to use a
+ RecordGrid in the identifyview.
+ (IdentifyView.__init__): Use IdentifyGridCtrl instead of
+ IdentifyListCtrl. The grid allows editing of the values.
+
+ * Thuban/UI/controls.py (RecordTable, RecordGridCtrl): New classes
+ implementing a grid for a single row of a thuban table.
+
+ * Thuban/UI/view.py (MapCanvas.SelectShapeAt): Search through all
+ layers by default. Easier to use than the previous default of only
+ searching through the select layer which meant that if no layer
+ was selected, you couldn't select a shape.
+
+ * Thuban/UI/tableview.py (TableGrid.__init__): Fix typo
+
+ * Thuban/UI/renderer.py (MapRenderer.draw_shape_layer): Honour the
+ stroke_width attribute
+
+ * Thuban/Model/save.py (save_session): Write the new stroke_width
+ attribute
+
+ * Thuban/Model/load.py (ProcessSession.startElement): Read the
+ stroke_width attribute
+
+ * Thuban/Model/layer.py (Layer.__init__): New parameter and
+ instance variable stroke_width
+ (Layer.SetStrokeWidth): Set the stroke_width.
+
+2002-02-01 Bernhard Herzog <bh at intevation.de>
+
+ * extensions/thuban/wxproj.cpp (project_points): Fix two
+ off-by-one errors in the last loop that joins the various parts
+ together.
+
+2002-01-14 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (data_dist.make_distribution): Fix some typos
+
+2001-09-18 Bernhard Herzog <bh at intevation.de>
+
+ * README: Slight tweaking in preparation for the 0.1 release
+
+ * setup.cfg: Add section for sdist to create both tgz and zip
+ archives
+
+ * setup.py: increase version number to 0.1
+ (data_dist): New command class for data distribution
+
+2001-09-14 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/identifyview.py (IdentifyListCtrl.selected_shape):
+ Handle the case of no layer (i.e. layer is None) properly.
+
+ * Thuban/UI/proj4dialog.py (UTMDialog.__init__, Proj4Dialog.__init__):
+ Set the initial selection of the combo boxes to reflect the
+ projection we're starting with in a way that works on windows,
+ too.
+
+ * Thuban/Lib/connector.py (Connector.print_connections): Print the
+ puiblisher's ids in hex to make it easier to compare them to the
+ standard repr of python methods
+
+ * Thuban/Model/map.py (Map.Destroy): Unsubscribe the label_layer
+ messages
+
+2001-09-13 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tree.py (SessionTreeCtrl.OnSelChanged): Make sure to
+ deselect the layer if no layer is selected
+
+ * Thuban/UI/view.py (MapCanvas.OnPaint): Only delay drawing to
+ idle time when there actually is something to draw. If there's
+ nothing to draw simply clear the window
+ (MapCanvas.do_redraw): Call dc.EndDrawing and add some comments.
+ (MapCanvas.SetMap): force a redraw in all cases because
+ FitMapToWindow doesn't always do it.
+ (MapCanvas.ZoomFactor): Add an optional parameter, center, to
+ specify the point to move into the center of the window
+ (ZoomOutTool.MouseUp, ZoomInTool.MouseUp): If the mouse wasn't
+ dragged, zoon in/out by a factor of 2
+ (MapCanvas.find_shape_at): Iterate backwards (i.e. with decreasing
+ index, i.e. reversed drawing order) so that objects appearing to
+ be in from of others are selected first. This is probably mostly
+ relevant for point shapes where the symbols used may overlap
+
+ * Thuban/Model/session.py (create_empty_session): Unset the
+ modified bit before returning it
+
+ * Thuban/UI/mainwindow.py (MainWindow.NewSession): Use
+ create_empty_session session to create the new, empty session.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): Set the size of
+ the tool bitmaps.
+ (MainWindow.OnClose, MainWindow.save_modified_session): Separate
+ the code that asks whether the session should be saved into the
+ new method save_modified_session.
+ (MainWindow.OpenSession, MainWindow.NewSession): Use the new
+ method to save modified session here too.
+
+2001-09-11 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py (InnoIconItem): fix typo
+
+ (thuban_bdist_inno.run):
+ (bdist_inno.run): Move the decision not to create symlinks on
+ non-nt platforms to thuban_bdist_inno and do it unconditinally
+ since we never want to create the symlinks here
+
+2001-09-10 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.IdentifyTool): Popup the
+ identify view immediately
+
+ * Thuban/UI/controls.py: New file with two classes RecordListCtrl
+ and SelectableRecordListCtrl that implement the code shared by the
+ identify view and the label dialog
+
+ * Thuban/UI/identifyview.py (IdentifyListCtrl): Derive from the
+ new class RecordListCtrl
+
+ * Thuban/UI/labeldialog.py (LabelDialog.OnOK): Check whether the
+ return value of GetValue is None instead of using it as a boolean
+ directly so that Zero numbers are handled properly.
+ (LabelListCtrl): Derive from the new class
+ SelectableRecordListCtrl
+
+ * Thuban/UI/proj4dialog.py (Proj4Dialog.__init__):
+ (Proj4Dialog.dialogLayout): Make the window resizable and set the
+ size of the text control explicitly to make the sizers work on
+ both Windows and X.
+
+2001-09-07 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.find_shape_at):Add a new parameter
+ that can limit the search to the currently selected layer.
+ (MapCanvas.SelectShapeAt): Make sure that the currently selected
+ layer stays selected even when no shape is found
+ (MapCanvas.FitRectToWindow): If the rect has zero with or zero
+ height do nothing (avoids zero division errors)
+
+2001-09-06 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/tree.py (SessionTreeCtrl, SessionTreeView.__init__):
+ Correct the spelling of SessionTreeCtrl. dabbrev is too damn
+ convenient :-)
+ (SessionTreeCtrl.__init__, SessionTreeCtrl.update_tree): Introduce
+ a new instvar layer_to_item to map layers to tree items
+ (SessionTreeCtrl.layer_selected): Select the appropriate tree item
+ to match the current selection in the interactor
+
+ * Thuban/UI/interactor.py (Interactor.SelectedLayer):
+ (Interactor.HasSelectedLayer): New methods to query the current
+ selection
+
+ * Thuban/UI/mainwindow.py (MainWindow.current_layer):
+ (MainWindow.has_selected_layer): Simply call the appropriate
+ interactor method
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__):
+ (MainWindow.LayerShowTable):
+ (MainWindow.identify_view_on_demand): Store the interactor in an
+ instvar and use that reference instead of going through main.app
+
+ * Thuban/UI/mainwindow.py (MainWindow.ShowSessionTree):
+ * Thuban/UI/application.py (ThubanApplication.OnInit):
+ * Thuban/UI/main.py (main): Create the session tree view in main
+ with the new mainwindow method ShowSessionTree and not directly
+ the application's OnInit method
+
+ * Thuban/UI/tree.py (myTreeCtrlPanel):
+ (SessioinTreeCtrl): Rename to SessioinTreeCtrl and turn it into a
+ TreeCtrl isntead of a panel. This affects most method since we now
+ refer to self instead of self.tree
+ (SessionTreeView): New class implementing a non-modal dialog
+ showing the session tree.
+
+ * Thuban/UI/mainwindow.py (MainWindow.LayerShowTable): Pass the
+ layer to the tableview dialog.
+
+ * Thuban/UI/tableview.py: Add some doc-strings
+ (TableGrid):
+ (TableGrid.OnRangeSelect):
+ (TableGrid.OnSelectCell):
+ (TableFrame.__init__):
+ (TableFrame.row_selected):
+ Selecting rows in the grid view now updates the selected shapes
+ through the TableFrame. To achieve this we derive TableGrid from
+ Publisher and introduce the message type ROW_SELECTED which the
+ TableFrame subscribes to and which is issued by OnRangeSelect and
+ OnSelectCell
+
+ (DataTable.SelectRow): Removed because it's no longer needed in
+ the row/shape selection scheme
+
+ * Thuban/UI/dialogs.py: New file implementing common classes for
+ dialogs
+
+ * Thuban/UI/tableview.py (TableGrid.__init__): Don't subscribe to
+ the SELECTED_SHAPE message anymore. This is now handled by the
+ parent.
+ (TableGrid.select_shape): Only update the selection if the shape
+ is not None.
+ (TableFrame): Inherit from the new NonModalDialog class.
+ (TableFrame.__init__, TableFrame.select_shape): Handle the
+ SELECT_SHAPE message.
+ (TableFrame.OnClose): Extend the inherited method to unsubscribe
+ SELECT_SHAPE
+
+ * Thuban/UI/mainwindow.py (MainWindow.init_dialogs):
+ (MainWindow.add_dialog):
+ (MainWindow.dialog_open):
+ (MainWindow.remove_dialog):
+ (MainWindow.get_open_dialog): New methods to maintain a dictionary
+ of opened non-modal dialogs.
+
+ (MainWindow.__init__): Initialize the new non-modal dictionary
+ management code
+ (MainWindow.LayerShowTable): maintain separate dialogs for each
+ table using the non-modal dialog management code to only open a
+ view once for each table.
+
+ (MainWindow.IdentifyTool):
+ (MainWindow.__init__):
+ (MainWindow.identify_view_on_demand): Don't open the identify view
+ in IdentifyTool anymore. This will be done automatically by the
+ new method identify_view_on_demand which handles the
+ SELECTED_SHAPE message so that the identify view will be opened on
+ demand
+
+ * Thuban/UI/identifyview.py (IdentifyListCtrl.__init__): Remove
+ the interactor argument. The SELECTED_SHAPE message is now handled
+ by the parent.
+ (IdentifyView.__init__): Add the interactor argument so that we
+ can handle the SELECTED_SHAPE message here
+ (IdentifyView.selected_shape): New method to handle the
+ SELECTED_SHAPE messages
+
+ * Thuban/UI/identifyview.py (IdentifyView): Derive from the new
+ NonModalDialog class
+ (IdentifyView.OnClose): Extend the inherited version to
+ unsubscribe SELECT_SHAPE
+
+ * Thuban/Model/session.py (Session.UnsetModified): Remove debug prints
+
+2001-09-05 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/view.py (MapCanvas.__init__): New argument, interactor.
+
+ * Thuban/UI/mainwindow.py (MainWindow.__init__): New argument
+ interactor to pass through to the MapCanvas
+
+ * Thuban/UI/application.py (ThubanApplication.OnInit): Use the new
+ argument to the MainWindow constructor to get rid of the ugly hack
+ that made main.app available early just so that the mapcanvas
+ could access the interactor object.
+
+2001-09-04 Bernhard Herzog <bh at intevation.de>
+
+ * Thuban/UI/mainwindow.py (MainWindow.RunMessageBox): New method
+ that runs a modal message box
+ (MainWindow.OnClose): Use the new method
+ (MainWindow.RemoveLayer): Just do nothing in case no layer is
+ selected. The command should be grayed out anyway, so there's no
+ need to pop up a message box.
+ (MainWindow.AddLayer): Pop up a message box with an error message
+ if the shape file can't be opened
+
+ * Thuban/Model/layer.py (Layer.__init__): Open the shapefile
+ immediately. This will cause an exception in case the file can't
+ be opened and we can display an appropriate message.
+
+ * MANIFEST.in: Add extensions/pyprojection/LICENSE
+
+ * setup.py (thuban_bdist_rpm): New class implementing a Thuban
+ specific bdist_rpm command.
+
+ * Thuban/UI/main.py: Catch ImportError exceptions when importing
+ the locale module because it may not be available on some
+ installations.
+
+ * extensions/pyprojection/LICENSE: Copy of the license text in
+ Projection.i. Having it in a separate file makes it easier to
+ refer to license text in e.g. RPMs
+
+2001-09-03 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: use wx-config instead of wxgtk-config because it's
+ more generic
+
+ * setup.py (ThubanInstall.get_outputs): Add the symlink in
+ <prefix>/bin to the outputs
+ (ThubanInstall.link_file): New method to link files. We need this
+ because the standard copy_files refuses to link non-existing
+ files.
+ (ThubanInstall.run): Remove the leading install root from the
+ script filename if an install root was specified and use the new
+ link_file method
+
+ * Thuban/UI/mainwindow.py (MainWindow.AddLayer): Fit the map to
+ the window when the first layer is added to the map.
+
+ * setup.py (ThubanInstall.run): Honor the build root (self.root)
+ when linking thuban.py to <prefix>/bin
+
+2001-08-31 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: In the setup call, the install parameters shouldn't
+ have trailing slashes because distutils on non-posix platforms
+ doesn't like that. The same applies to other directories like
+ "Resources/Bitmaps"
+
+ In the configuration section for nt, move the wxWindows directory
+ optins into the part clearly marked as editable.
+
+ (InstallLocal.initialize_options):
+ (InstallLocal.user_options): remove the currently unused debug
+ flag
+ (thuban_build_py.find_all_modules): Add this method so that it
+ works for our case of having packages and modules in one
+ distribution as well.
+ (ThubanInstall.initialize_options):
+ (ThubanInstall.finalize_options):
+ (ThubanInstall.user_options):
+ (ThubanInstall.boolean_options): Add new options, do-symlink and
+ extra files. Since these are the first ThubanInstall specific
+ options, override user_options and boolean_options
+ (ThubanInstall.run): Honor the new do-symlink and extra-files
+ options.
+ (ThubanInstall.get_outputs): Add to override the base-class's
+ version and add the extra-files to the outputs
+ (bdist_inno): New class for windows distributions with Inno Setup
+ (InnoIconItem): Helper class for bdist_inno
+ (thuban_bdist_inno): Thuban specific version of bdist_inno. Added
+ this together with the appropriate parameters, to the setup call.
+
+ * setup.cfg (bdist_inno): added new section for the inno setup
+ installer
+
+ * Thuban/UI/tree.py (myTreeCtrlPanel.__init__): New inst var
+ changing_selection to avoid recursive selection events when
+ modifying the selection in response to a selection event.
+ (myTreeCtrlPanel.normalize_selection): Set the new inst var when
+ changing the tree's selection.
+ (myTreeCtrlPanel.OnSelChanged): Only normalize the selection when
+ we're not being called indirectly from normalize_selection.
+
+ * Thuban/UI/mainwindow.py (MainWindow.update_command_ui): Call
+ event.Check only if the command is actuall checkable.
+ (MainWindow.__init__): Call the toolbar's Realize method to make
+ sure that the items are actually shown
+
+2001-08-28 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: Fix some doc strings
+
+ * ChangeLog: started
+
Added: packages/thuban/branches/upstream/current/Doc/README
===================================================================
--- packages/thuban/branches/upstream/current/Doc/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+$Id: README 2728 2007-02-20 10:51:07Z bernhard $
+
+Currently, there is no explicit document on the implementation
+details but a UML description of the Model Module:
+ ThubanModul.xmi
+You can edit this file with Umbrello.
+
+Furthermore, you can generate class and method description
+automatically from the source code:
+
+pydoc coming with Python can be quite useful as a class browser.
+If you want to use it on Thuban, you need to give it the right
+paths so you can browse all of it.
+
+e.g. , the following starts pydoc as webbrowser on localhost:1234/
+ cd thuban
+ PYTHONPATH=./Lib:./test/ pydoc -p 1234
+
+A brief look into other documentation tools
+resulted in that the the best overview about them was coming with
+epydoc at:
+http://epydoc.sourceforge.net/relatedprojects.html
+
+epydoc seems to be very solid, because the author did a lot
+of reseach and decided for a very simple markup language.
+It might be surpassed one day by docutils which use the more
+complicated reStructured text as markup.
+
+As nice side contender is happydoc, because it does not import
+the python modules.
Added: packages/thuban/branches/upstream/current/Doc/ThubanModel.org.xmi
===================================================================
--- packages/thuban/branches/upstream/current/Doc/ThubanModel.org.xmi 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/ThubanModel.org.xmi 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1528 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<XMI xmlns:UML="org.omg/standards/UML" verified="false" timestamp="" xmi.version="1.2" >
+ <XMI.header>
+ <XMI.documentation>
+ <XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
+ <XMI.exporterVersion>1.2.0</XMI.exporterVersion>
+ <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
+ </XMI.documentation>
+ <XMI.model xmi.name="ThubanModel" href="/home/janschu/checka/ThubanModel.xmi" />
+ <XMI.metamodel xmi.name="UML" href="UML.xml" xmi.version="1.3" />
+ </XMI.header>
+ <XMI.content>
+ <docsettings viewid="174" documentation="" uniqueid="1356" />
+ <UML:Model>
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="175" name="int" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="176" name="char" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="177" name="bool" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="178" name="float" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="179" name="double" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="180" name="long" />
+ <UML:DataType stereotype="datatype" visibility="public" xmi.id="181" name="short" />
+ <UML:Package visibility="public" xmi.id="186" name="Model.base" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="194" name="Modifiable" >
+ <UML:Operation visibility="public" xmi.id="889" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="890" type="void" name="changed" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="string" name="channel" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="*.args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="891" type="void" name="__init__" />
+ <UML:Operation visibility="public" xmi.id="892" type="bool" name="WasModified" />
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="195" name="TitledObject" >
+ <UML:Operation visibility="public" xmi.id="919" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="920" type="string" name="Title" />
+ <UML:Operation visibility="public" xmi.id="921" type="void" name="SetTitle" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package stereotype="Lib" visibility="public" xmi.id="188" name="Lib.connector" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="189" name="Publisher" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="196" name="Model.messages" />
+ <UML:Package visibility="public" xmi.id="198" name="Model.label" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="199" name="Label" >
+ <UML:Operation visibility="public" xmi.id="928" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="x" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="y" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="string" name="text" />
+ <UML:Parameter visibility="public" xmi.id="4" value="" type="string" name="halign" />
+ <UML:Parameter visibility="public" xmi.id="5" value="" type="string" name="valign" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="200" name="LabelLayer" >
+ <UML:Operation visibility="public" xmi.id="923" type="void" name="AddLabel" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="x" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="y" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="string" name="text" />
+ <UML:Parameter visibility="public" xmi.id="4" value="left" type="string" name="halign" />
+ <UML:Parameter visibility="public" xmi.id="5" value="center" type="string" name="valign" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="924" type="void" name="ClearLabels" />
+ <UML:Operation visibility="public" xmi.id="925" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="926" type="void" name="Labels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Label" name="labels" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="927" type="void" name="RemoveLabels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="207" name="Model.classification" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="208" name="ClassGroup" >
+ <UML:Operation visibility="public" xmi.id="1184" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1185" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1186" type="Label" name="GetLabel" />
+ <UML:Operation visibility="public" xmi.id="1187" type="ClassGroupProperties" name="GetProperties" />
+ <UML:Operation visibility="public" xmi.id="1188" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1189" type="bool" name="IsVisible" />
+ <UML:Operation visibility="public" xmi.id="1190" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1191" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1192" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1193" type="void" name="SetLabel" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="label" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1194" type="void" name="SetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="prop" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1195" type="void" name="SetVisible" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="bool" name="visible" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="209" name="ClassGroupDefault" >
+ <UML:Operation visibility="public" xmi.id="1196" type="ClassGroupDefault" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1197" type="ClassGroupDefault" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="memo" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1198" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1199" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1200" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="2" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1201" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1202" type="string" name="__repr__" />
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="210" name="ClassGroupMap" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="211" name="ClassGroupProperties" >
+ <UML:Operation visibility="public" xmi.id="1241" type="ClassGroupProperties" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1242" type="ClassGroupProperties" name="__deepcopy__" />
+ <UML:Operation visibility="public" xmi.id="1243" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1244" type="Color" name="GetFill" />
+ <UML:Operation visibility="public" xmi.id="1245" type="Color" name="GetLineColor" />
+ <UML:Operation visibility="public" xmi.id="1246" type="int" name="GetLineWidth" />
+ <UML:Operation visibility="public" xmi.id="1247" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="ClassGroupProperties" name="props" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1248" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1249" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1250" type="void" name="SetFill" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="fill" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1251" type="void" name="SetLineColor" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1252" type="void" name="SetLineWidth" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="lineWidth" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1253" type="void" name="SetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="props" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="212" name="ClassGroupRange" >
+ <UML:Operation visibility="public" xmi.id="1209" type="ClassGroupRange" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1210" type="ClassGroupRange" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="mono" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1211" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClasGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1212" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1213" type="int" name="GetMax" />
+ <UML:Operation visibility="public" xmi.id="1214" type="int" name="GetMin" />
+ <UML:Operation visibility="public" xmi.id="1215" type="string" name="GetRange" />
+ <UML:Operation visibility="public" xmi.id="1216" type="string" name="GetRangeTuple" />
+ <UML:Operation visibility="public" xmi.id="1217" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="(0, 1)" type="int2 or ClassGroupRange" name="_range" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1218" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1219" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1220" type="void" name="SetMax" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="max" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1221" type="void" name="SetMin" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="min" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1222" type="void" name="SetRange" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int2 or Range" name="_range" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="213" name="ClassGroupSingleton" >
+ <UML:Operation visibility="public" xmi.id="1232" type="ClassGroupSingleton" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1233" type="ClassGroupSingleton" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="mono" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1234" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1235" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1236" type="float" name="GetValue" />
+ <UML:Operation visibility="public" xmi.id="1237" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="0" type="float" name="value" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1238" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1239" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1240" type="void" name="SetValue" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="214" name="Classification" >
+ <UML:Operation visibility="public" xmi.id="1154" type="void" name="AppendGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="item" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="1155" type="string" name="build_color_item" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="1156" type="string" name="build_item" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="string" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1157" type="void" name="_clear_compiled_classification" />
+ <UML:Operation visibility="public" xmi.id="1158" type="void" name="_compile_classification" />
+ <UML:Operation visibility="public" xmi.id="1159" type="Classification" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="memo" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1160" type="ClassGroup" name="FindGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1161" type="void" name="__getattr__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="attr" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1162" type="Color" name="GetDefaultFill" />
+ <UML:Operation visibility="public" xmi.id="1163" type="ClassGroupDefault" name="GetDefaultGroup" />
+ <UML:Operation visibility="public" xmi.id="1164" type="Color" name="GetDefaultLineColor" />
+ <UML:Operation visibility="public" xmi.id="1165" type="int" name="GetDefaultLineWidth" />
+ <UML:Operation visibility="public" xmi.id="1166" type="ClassGroup" name="GetGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1167" type="int" name="GetNumGroups" />
+ <UML:Operation visibility="public" xmi.id="1168" type="ClassGroupProperties" name="GetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1169" type="void" name="__init__" />
+ <UML:Operation visibility="public" xmi.id="1170" type="void" name="InsertGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1171" type="ClassIterator" name="__iter__" />
+ <UML:Operation visibility="public" xmi.id="1172" type="void" name="RemoveGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1173" type="void" name="ReplaceGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1174" type="void" name="__SendNotification" />
+ <UML:Operation visibility="public" xmi.id="1175" type="void" name="SetDefaultFill" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="fill" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1177" type="void" name="SetDefaultGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1178" type="void" name="SetDefaultLineColor" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1179" type="void" name="SetDefaultLineWidth" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="lineWidth" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1180" type="string[]" name="TreeInfo" />
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="215" name="ClassIterator" >
+ <UML:Operation visibility="public" xmi.id="1181" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup[]" name="data" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1182" type="ClassIterator" name="__iter__" />
+ <UML:Operation visibility="public" xmi.id="1183" type="ClassGroup" name="next" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="216" name="Model.color" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="217" name="Color" >
+ <UML:Operation visibility="public" xmi.id="1258" type="void" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1259" type="string" name="hex" />
+ <UML:Operation visibility="public" xmi.id="1260" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="red" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="green" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="int" name="blue" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1261" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1262" type="string" name="__repr__" />
+ </UML:Class>
+ <UML:Class stereotype="class" comment="An object which represents no color." visibility="private" xmi.id="218" name="_Transparent" >
+ <UML:Operation visibility="public" xmi.id="1254" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Object" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1255" type="string" name="hex" />
+ <UML:Operation visibility="public" xmi.id="1256" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Object" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1257" type="string" name="__repr__" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="219" name="Model.extension" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="220" name="Extension" >
+ <UML:Operation visibility="public" xmi.id="1143" type="void" name="AddObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ObjectfromExtension" name="object" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1144" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1145" type="ObjectfromExtension" name="FindObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1146" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*.args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1147" type="bool" name="HasObjects" />
+ <UML:Operation visibility="public" xmi.id="1148" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1149" type="ObjectfromExtension[]" name="Objects" />
+ <UML:Operation visibility="public" xmi.id="1150" type="void" name="RemoveObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ObjectfromExtension" name="object" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1151" type="string[]" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1152" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1153" type="int" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="224" name="Model.layer" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="225" name="BaseLayer" >
+ <UML:Operation visibility="public" xmi.id="931" type="Projection" name="GetProjection" />
+ <UML:Operation visibility="public" xmi.id="932" type="bool" name="HasClassification" />
+ <UML:Operation visibility="public" xmi.id="933" type="bool" name="HasShapes" />
+ <UML:Operation visibility="public" xmi.id="934" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="True" type="bool" name="visible" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="935" type="void" name="SetProjection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="936" type="void" name="SetVisible" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="937" type="bool" name="Visible" />
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="226" name="Layer" >
+ <UML:Operation visibility="public" xmi.id="943" type="tuple(int,int,int,int)" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="944" type="void" name="_classification_changed" />
+ <UML:Operation visibility="public" xmi.id="945" type="tuple(int,int,int,int)" name="ClipBoundingBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(int,int,int,int)" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="946" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="947" type="string" name="GetClassificationColumn" />
+ <UML:Operation visibility="public" xmi.id="948" type="Classification" name="GetClassification" />
+ <UML:Operation visibility="public" xmi.id="949" type="Column.type" name="GetFieldType" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="fieldName" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="950" type="bool" name="HasClassification" />
+ <UML:Operation visibility="public" xmi.id="951" type="bool" name="HasShapes" />
+ <UML:Operation visibility="public" xmi.id="952" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="Shape data" name="data" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ <UML:Parameter visibility="public" xmi.id="4" value="Transparent" type="Color" name="fill" />
+ <UML:Parameter visibility="public" xmi.id="5" value="Black" type="Color" name="stroke" />
+ <UML:Parameter visibility="public" xmi.id="6" value="1" type="int" name="lineWidth" />
+ <UML:Parameter visibility="public" xmi.id="7" value="True" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="953" type="bbox" name="LatLongBoundingBox" />
+ <UML:Operation visibility="public" xmi.id="954" type="int" name="NumShapes" />
+ <UML:Operation visibility="public" xmi.id="955" type="void" name="SetClassificationColumn" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="column" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="956" type="void" name="SetClassification" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Classification" name="clazz" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="957" type="void" name="SetShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="shapestore" name="store" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="958" type="tuple(int,int,int,int)" name="ShapesBoundingBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="shapes" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="959" type="Shape" name="Shapes" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="960" type="Shapes" name="ShapesInRegion" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(int,int,int,int)" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="962" type="shapestore" name="ShapeStore" />
+ <UML:Operation visibility="public" xmi.id="963" type="constanten" name="ShapeType" />
+ <UML:Operation visibility="public" xmi.id="964" type="string()" name="TreeInfo" />
+ </UML:Class>
+ <UML:Class stereotype="class" visibility="public" xmi.id="227" name="RasterLayer" >
+ <UML:Operation visibility="public" xmi.id="938" type="tuple(int,int,int,int))" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="939" type="string" name="GetImageFilename" />
+ <UML:Operation visibility="public" xmi.id="940" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="string" name="filename" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ <UML:Parameter visibility="public" xmi.id="4" value="True" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="941" type="tuple(int,int,int,int)" name="LatLongBox" />
+ <UML:Operation visibility="public" xmi.id="942" type="tuple(string, array(string))" name="TreeInfo" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="232" name="Model.map" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="233" name="Map" >
+ <UML:Operation visibility="public" xmi.id="1060" type="void" name="AddLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1061" type="int4" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="1062" type="int" name="CanRemoveLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1063" type="void" name="ClearLayers" />
+ <UML:Operation visibility="public" xmi.id="1064" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1065" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1066" type="Projection" name="GetProjection" />
+ <UML:Operation visibility="public" xmi.id="1067" type="bool" name="HasLayers" />
+ <UML:Operation visibility="public" xmi.id="1068" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1069" type="LabelLayer" name="LabelLayer" />
+ <UML:Operation visibility="public" xmi.id="1070" type="Layer[]" name="Layers" />
+ <UML:Operation visibility="public" xmi.id="1071" type="void" name="LowerLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1072" type="void" name="MoveLayerToBottom" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1073" type="void" name="MoveLayerToTop" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1074" type="int4" name="ProjectedBoundingBox" />
+ <UML:Operation visibility="public" xmi.id="1075" type="void" name="RaiseLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1076" type="void" name="RemoveLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1077" type="void" name="SetProjection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1078" type="void" name="subscribe_layer_channels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1079" type="void" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1080" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1081" type="void" name="unsubscribe_layer_channels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1082" type="string()" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="236" name="Model.proj" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="237" name="BaseProjection" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="238" name="ProjFile" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="733" name="Projection" >
+ <UML:Operation visibility="public" xmi.id="991" type="string" name="EPSGCode" />
+ <UML:Operation visibility="public" xmi.id="992" type="int()" name="ForwardBBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int()" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="993" type="string[]" name="GetAllParameters" />
+ <UML:Operation visibility="public" xmi.id="994" type="string" name="GetName" />
+ <UML:Operation visibility="public" xmi.id="995" type="string" name="GetParameter" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="param" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="996" type="int" name="GetProjectedUnits" />
+ <UML:Operation visibility="public" xmi.id="997" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="stinr[]" name="params" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="string" name="name" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="string" name="epsg" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="998" type="int()" name="InverseBBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int()" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="999" type="string" name="Label" />
+ <UML:Operation visibility="public" xmi.id="1000" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1001" type="int(4)" name="_transform_bbox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Trafo" name="trafo" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int(4)" name="bbox" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="239" name="Model.session" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="240" name="AutoRemoveDir" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="241" name="AutoRemoveFile" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="242" name="Session" >
+ <UML:Operation visibility="public" xmi.id="1083" type="void" name="AddDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1084" type="void" name="AddExtension" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Extension" name="extension" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1085" type="void" name="AddMap" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Map" name="map" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1086" type="void" name="AddShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ShapefileStore" name="shapestore" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1087" type="void" name="_add_shapestore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ShapefileStore" name="store" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1088" type="void" name="AddTable" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="AutoTransientTable" name="table" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1089" type="int" name="CanRemoveDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1090" type="void" name="changed" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="" name="channel" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1091" type="void" name="_clean_weak_store_refs" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="weakref" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1092" type="data containers" name="DataContainers" />
+ <UML:Operation visibility="public" xmi.id="1093" type="PostGISConnection" name="DBConnections" />
+ <UML:Operation visibility="public" xmi.id="1094" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1095" type="Extension[]" name="Extensions" />
+ <UML:Operation visibility="public" xmi.id="1096" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1097" type="int" name="HasDBConnections" />
+ <UML:Operation visibility="public" xmi.id="1098" type="int" name="HasExtensions" />
+ <UML:Operation visibility="public" xmi.id="1099" type="int" name="HasMaps" />
+ <UML:Operation visibility="public" xmi.id="1100" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1101" type="Map[]" name="Maps" />
+ <UML:Operation visibility="public" xmi.id="1102" type="ShapefileStore" name="OpenDBShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="db" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="string" name="tablename" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="string" name="id_column" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="string" name="geometry_column" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1103" type="ShapefileStore" name="OpenShapefile" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1104" type="DBFTable" name="OpenTableFile" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1105" type="void" name="RemoveDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1106" type="void" name="RemoveMap" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Map" name="map" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1107" type="void" name="RemoveTable" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="*Table" name="table" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1108" type="void" name="SetFilename" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1109" type="ShapefileStore[]" name="ShapeStores" />
+ <UML:Operation visibility="public" xmi.id="1110" type="*Tables[]" name="Tables" />
+ <UML:Operation visibility="public" xmi.id="1111" type="string" name="temp_directory" />
+ <UML:Operation visibility="public" xmi.id="1112" type="TransientDatabase" name="TransientDB" />
+ <UML:Operation visibility="public" xmi.id="1113" type="string[]" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1114" type="*Tables[]" name="UnreferencedTables" />
+ <UML:Operation visibility="public" xmi.id="1115" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1116" type="int" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="261" name="Model.range" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="262" name="Range" >
+ <UML:Operation visibility="public" xmi.id="1223" type="bool" name="__contains__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1224" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Range" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1225" type="string" name="_float2string" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1226" type="string4" name="GetRange" />
+ <UML:Operation visibility="public" xmi.id="1227" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="string" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1228" type="void" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Range" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1229" type="void" name="_SetRange" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1230" type="string" name="string" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(string,int,int,string)" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1231" type="string" name="__str__" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="264" name="Model.data" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="265" name="DerivedShapeStore" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="266" name="ShapefileShape" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="267" name="ShapefileStore" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="268" name="ShapeTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="269" name="Model.load" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="270" name="AttrDesc" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="271" name="LoadCancelled" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="272" name="LoadError" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="273" name="SessionLoader" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="280" name="Model.classgen" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="281" name="CustomRamp" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="282" name="FixedRamp" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="283" name="HotToColdRamp" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="284" name="MonochromaticRamp" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="285" name="Model.postgisdb" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="286" name="ConnectionError" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="287" name="PostGISColumn" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="288" name="PostGISConnection" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="289" name="PostGISShape" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="291" name="PostGISTable" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="825" name="PostGISShapeStore" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="292" name="Model.resource" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="293" name="ProjFileReader" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="294" name="ProjFileSaver" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="295" name="Model.save" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="296" name="SessionSaver" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="297" name="Model.scalebar" />
+ <UML:Package visibility="public" xmi.id="298" name="Model.table" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="299" name="DBFColumn" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="300" name="DBFTable" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="301" name="MemoryColumn" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="302" name="MemoryTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="303" name="Model.transientdb" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="304" name="AutoTransientTable" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="305" name="ColiumnReference" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="306" name="TransientDatabase" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="307" name="TransientJoinedTable" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="308" name="TransientTableBase" />
+ <UML:Class stereotype="class" visibility="public" xmi.id="309" name="TransientTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="310" name="Model.wellknowntext" />
+ <UML:Package visibility="public" xmi.id="311" name="Model.xmlreader" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="313" name="XMLReader" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="312" name="Model.xmlwriter" >
+ <UML:Class stereotype="class" visibility="public" xmi.id="314" name="XMLWriter" />
+ </UML:Package>
+ <UML:Association visibility="public" xmi.id="201" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="200" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="202" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="194" />
+ <UML:AssociationEndRole visibility="public" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="203" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="200" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="206" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="194" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="221" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="220" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="222" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="220" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="228" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="225" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="229" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="225" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="230" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="226" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="225" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="231" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="227" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="225" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="234" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="235" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="243" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="242" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="244" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="242" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="251" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="210" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="252" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="212" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="253" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="213" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="254" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="214" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="263" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="218" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="316" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="195" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="318" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" type="233" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="341" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="227" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="226" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="194" visibility="public" xmi.id="600" parent="189" />
+ <UML:Generalization child="200" visibility="public" xmi.id="602" parent="195" />
+ <UML:Generalization child="200" visibility="public" xmi.id="603" parent="194" />
+ <UML:Association visibility="public" xmi.id="605" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="200" />
+ <UML:AssociationEndRole visibility="public" type="199" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="225" visibility="public" xmi.id="615" parent="195" />
+ <UML:Generalization child="225" visibility="public" xmi.id="616" parent="194" />
+ <UML:Generalization child="220" visibility="public" xmi.id="625" parent="194" />
+ <UML:Generalization child="220" visibility="public" xmi.id="626" parent="195" />
+ <UML:Generalization child="233" visibility="public" xmi.id="645" parent="194" />
+ <UML:Generalization child="233" visibility="public" xmi.id="646" parent="195" />
+ <UML:Generalization child="242" visibility="public" xmi.id="655" parent="194" />
+ <UML:Generalization child="242" visibility="public" xmi.id="656" parent="195" />
+ <UML:Generalization child="227" visibility="public" xmi.id="669" parent="225" />
+ <UML:Generalization child="226" visibility="public" xmi.id="670" parent="225" />
+ <UML:Generalization child="214" visibility="public" xmi.id="679" parent="189" />
+ <UML:Association visibility="public" xmi.id="681" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="214" />
+ <UML:AssociationEndRole visibility="public" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="209" visibility="public" xmi.id="695" parent="208" />
+ <UML:Generalization child="212" visibility="public" xmi.id="705" parent="208" />
+ <UML:Generalization child="213" visibility="public" xmi.id="706" parent="208" />
+ <UML:Association visibility="public" xmi.id="708" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="226" />
+ <UML:AssociationEndRole visibility="public" type="214" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="715" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="208" />
+ <UML:AssociationEndRole visibility="public" type="211" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="716" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="211" />
+ <UML:AssociationEndRole visibility="public" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="721" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="242" />
+ <UML:AssociationEndRole visibility="public" type="233" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="722" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="242" />
+ <UML:AssociationEndRole visibility="public" type="220" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="731" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="233" />
+ <UML:AssociationEndRole visibility="public" type="226" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="732" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="233" />
+ <UML:AssociationEndRole visibility="public" type="227" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="816" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="212" />
+ <UML:AssociationEndRole visibility="public" type="262" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1058" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="233" />
+ <UML:AssociationEndRole visibility="public" type="733" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1059" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="226" />
+ <UML:AssociationEndRole visibility="public" type="733" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1263" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="214" />
+ <UML:AssociationEndRole visibility="public" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ </UML:Model>
+ <diagrams>
+ <diagram snapgrid="1" showattsig="1" fillcolor="#ffffc0" zoom="64" showgrid="1" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="5034" snapy="10" showatts="1" xmi.id="174" documentation="" type="402" showops="1" showpackage="0" name="class diagram" localid="30000" showstereotype="0" showscope="1" snapcsgrid="1" font="helvetica,12,-1,0,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="2844" >
+ <widgets>
+ <UML:ClassWidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="2420" linecolour="#ff0000" y="410" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="120" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="194" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="240" showattsigs="601" usesdiagramusefillcolour="0" x="3090" linecolour="#ff0000" y="410" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="100" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="195" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="1" width="230" showattsigs="601" usesdiagramusefillcolour="1" x="2490" linecolour="none" y="170" showopsigs="601" instancename="" usesdiagramlinecolour="1" fillcolour="none" height="40" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="189" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="helvetica,12,-1,0,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="710" showattsigs="601" usesdiagramusefillcolour="0" x="4320" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="200" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="580" showattsigs="601" usesdiagramusefillcolour="0" x="4390" linecolour="#ff0000" y="1220" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="60" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="199" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="640" showattsigs="601" usesdiagramusefillcolour="0" x="3660" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="180" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="225" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="420" showattsigs="601" usesdiagramusefillcolour="0" x="1540" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="270" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="220" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="1030" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="580" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="214" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="480" showattsigs="601" usesdiagramusefillcolour="0" x="3160" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="520" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="233" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="1110" showattsigs="601" usesdiagramusefillcolour="0" x="2000" linecolour="#ff0000" y="1010" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="750" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="242" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="1310" showattsigs="601" usesdiagramusefillcolour="0" x="3500" linecolour="#ff0000" y="1770" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="480" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="226" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="770" showattsigs="601" usesdiagramusefillcolour="0" x="4230" linecolour="#ff0000" y="1530" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="227" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="780" showattsigs="601" usesdiagramusefillcolour="0" x="890" linecolour="#ff0000" y="1850" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="290" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="208" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="780" showattsigs="601" usesdiagramusefillcolour="0" x="1170" linecolour="#ff0000" y="2230" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="180" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="209" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="2380" linecolour="#ff0000" y="2530" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="310" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="211" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="1100" showattsigs="601" usesdiagramusefillcolour="0" x="790" linecolour="#ff0000" y="2510" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="330" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="212" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="910" showattsigs="601" usesdiagramusefillcolour="0" x="2280" linecolour="#ff0000" y="1980" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="220" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="213" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="300" showattsigs="601" usesdiagramusefillcolour="0" x="880" linecolour="#ff0000" y="1700" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="100" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="215" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="380" showattsigs="601" usesdiagramusefillcolour="0" x="2590" linecolour="#ff0000" y="2260" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="217" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="250" showattsigs="601" usesdiagramusefillcolour="0" x="2830" linecolour="#ff0000" y="2530" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="120" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="218" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="610" showattsigs="601" usesdiagramusefillcolour="0" x="3120" linecolour="#ff0000" y="2480" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="270" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="733" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <UML:ClassWidget usesdiagramfillcolour="0" width="400" showattsigs="601" usesdiagramusefillcolour="0" x="1950" linecolour="#ff0000" y="2570" showopsigs="601" instancename="" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="220" usefillcolor="1" showattributes="1" isinstance="0" xmi.id="262" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ </widgets>
+ <messages/>
+ <associations>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="189" widgetaid="194" xmi.id="600" >
+ <linepath>
+ <startpoint startx="2635" starty="410" />
+ <endpoint endx="2643" endy="210" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="6" indexb="5" widgetbid="195" widgetaid="200" xmi.id="602" >
+ <linepath>
+ <startpoint startx="4793" starty="1010" />
+ <endpoint endx="3290" endy="510" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="6" indexb="5" widgetbid="194" widgetaid="200" xmi.id="603" >
+ <linepath>
+ <startpoint startx="4556" starty="1010" />
+ <endpoint endx="2778" endy="530" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="199" widgetaid="200" xmi.id="605" >
+ <linepath>
+ <startpoint startx="4675" starty="1150" />
+ <endpoint endx="4680" endy="1220" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="6" indexb="4" widgetbid="195" widgetaid="225" xmi.id="615" >
+ <linepath>
+ <startpoint startx="4086" starty="1010" />
+ <endpoint endx="3250" endy="510" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="6" indexb="4" widgetbid="194" widgetaid="225" xmi.id="616" >
+ <linepath>
+ <startpoint startx="3873" starty="1010" />
+ <endpoint endx="2706" endy="530" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="6" indexb="1" widgetbid="194" widgetaid="220" xmi.id="625" >
+ <linepath>
+ <startpoint startx="1680" starty="1010" />
+ <endpoint endx="2491" endy="530" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="6" indexb="1" widgetbid="195" widgetaid="220" xmi.id="626" >
+ <linepath>
+ <startpoint startx="1820" starty="1010" />
+ <endpoint endx="3130" endy="510" />
+ <point x="1860" y="980" />
+ <point x="2660" y="690" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="6" indexb="3" widgetbid="194" widgetaid="233" xmi.id="645" >
+ <linepath>
+ <startpoint startx="3320" starty="1010" />
+ <endpoint endx="2635" endy="530" />
+ <point x="3060" y="840" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="6" indexb="3" widgetbid="195" widgetaid="233" xmi.id="646" >
+ <linepath>
+ <startpoint startx="3480" starty="1010" />
+ <endpoint endx="3210" endy="510" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="6" indexb="2" widgetbid="194" widgetaid="242" xmi.id="655" >
+ <linepath>
+ <startpoint startx="2370" starty="1010" />
+ <endpoint endx="2563" endy="530" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="6" indexb="2" widgetbid="195" widgetaid="242" xmi.id="656" >
+ <linepath>
+ <startpoint startx="2740" starty="1010" />
+ <endpoint endx="3170" endy="510" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="225" widgetaid="227" xmi.id="669" >
+ <linepath>
+ <startpoint startx="4615" starty="1530" />
+ <endpoint endx="4086" endy="1190" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="225" widgetaid="226" xmi.id="670" >
+ <linepath>
+ <startpoint startx="4155" starty="1770" />
+ <endpoint endx="3873" endy="1190" />
+ <point x="4120" y="1960" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="189" widgetaid="214" xmi.id="679" >
+ <linepath>
+ <startpoint startx="1245" starty="1010" />
+ <endpoint endx="2566" endy="210" />
+ <point x="1250" y="980" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="2" indexb="1" widgetbid="208" widgetaid="214" xmi.id="681" >
+ <linepath>
+ <startpoint startx="1173" starty="1590" />
+ <endpoint endx="1280" endy="1850" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="208" widgetaid="209" xmi.id="695" >
+ <linepath>
+ <startpoint startx="1560" starty="2230" />
+ <endpoint endx="1410" endy="2140" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="208" widgetaid="212" xmi.id="705" >
+ <linepath>
+ <startpoint startx="1340" starty="2510" />
+ <endpoint endx="1150" endy="2140" />
+ <point x="1150" y="2440" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="208" widgetaid="213" xmi.id="706" >
+ <linepath>
+ <startpoint startx="2280" starty="2090" />
+ <endpoint endx="1670" endy="1946" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" visibilityB="200" totalcountb="3" indexb="2" widgetbid="214" widgetaid="215" roleBdoc="" roleAdoc="" type="503" changeabilityA="900" changeabilityB="900" visibilityA="200" >
+ <linepath>
+ <startpoint startx="1030" starty="1700" />
+ <endpoint endx="1316" endy="1590" />
+ <point x="1140" y="1640" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="3" indexb="1" widgetbid="214" widgetaid="226" xmi.id="708" >
+ <linepath>
+ <startpoint startx="3500" starty="1930" />
+ <endpoint endx="1460" endy="1203" />
+ <point x="1940" y="1870" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2710" linecolour="none" y="2010" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="708" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3490" linecolour="none" y="2000" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="708" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="1420" linecolour="none" y="1200" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="708" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="3470" linecolour="none" y="1960" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="708" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1430" linecolour="none" y="1200" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="708" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="211" widgetaid="208" xmi.id="715" >
+ <linepath>
+ <startpoint startx="1670" starty="2043" />
+ <endpoint endx="2523" endy="2530" />
+ <point x="1890" y="2080" />
+ <point x="2090" y="2370" />
+ <point x="2360" y="2460" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2700" linecolour="none" y="2630" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="715" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="1650" linecolour="none" y="1990" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="715" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2510" linecolour="none" y="2540" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="715" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1660" linecolour="none" y="2020" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="715" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2490" linecolour="none" y="2510" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="715" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="217" widgetaid="211" xmi.id="716" >
+ <linepath>
+ <startpoint startx="2666" starty="2530" />
+ <endpoint endx="2716" endy="2400" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2480" linecolour="none" y="2650" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="716" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2340" linecolour="none" y="2680" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="716" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2720" linecolour="none" y="2370" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="716" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2350" linecolour="none" y="2730" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="716" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2690" linecolour="none" y="2380" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="716" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" visibilityB="200" totalcountb="3" indexb="2" widgetbid="217" widgetaid="218" roleBdoc="" roleAdoc="" type="503" changeabilityA="900" changeabilityB="900" visibilityA="200" >
+ <linepath>
+ <startpoint startx="2955" starty="2530" />
+ <endpoint endx="2843" endy="2400" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="233" widgetaid="242" xmi.id="721" >
+ <linepath>
+ <startpoint startx="3110" starty="1385" />
+ <endpoint endx="3160" endy="1270" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3100" linecolour="none" y="1310" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="721" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3030" linecolour="none" y="1370" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="721" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3150" linecolour="none" y="1220" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="721" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="3030" linecolour="none" y="1330" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="721" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="3130" linecolour="none" y="1260" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="721" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="220" widgetaid="242" xmi.id="722" >
+ <linepath>
+ <startpoint startx="2000" starty="1385" />
+ <endpoint endx="1750" endy="1280" />
+ <point x="1810" y="1370" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="2010" linecolour="none" y="1450" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="722" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="1980" linecolour="none" y="1400" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="722" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="1550" linecolour="none" y="1350" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="722" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1970" linecolour="none" y="1330" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="722" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1550" linecolour="none" y="1390" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="722" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="3" indexb="2" widgetbid="226" widgetaid="233" xmi.id="731" >
+ <linepath>
+ <startpoint startx="3480" starty="1530" />
+ <endpoint endx="3500" endy="2090" />
+ <point x="3810" y="1940" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="227" widgetaid="233" xmi.id="732" >
+ <linepath>
+ <startpoint startx="3640" starty="1270" />
+ <endpoint endx="4230" endy="1600" />
+ <point x="4200" y="1570" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="262" widgetaid="212" xmi.id="816" >
+ <linepath>
+ <startpoint startx="1890" starty="2675" />
+ <endpoint endx="1950" endy="2680" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="3" indexb="1" widgetbid="733" widgetaid="233" xmi.id="1058" >
+ <linepath>
+ <startpoint startx="3320" starty="1530" />
+ <endpoint endx="3323" endy="2480" />
+ </linepath>
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3360" linecolour="none" y="2030" instancename="" posttext="" usesdiagramlinecolour="1" role="703" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="1058" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3300" linecolour="none" y="1500" instancename="" posttext="" usesdiagramlinecolour="1" role="701" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="1058" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="10" usesdiagramusefillcolour="1" x="3310" linecolour="none" y="2450" instancename="" posttext="" usesdiagramlinecolour="1" role="702" fillcolour="none" height="30" usefillcolor="1" pretext="" isinstance="0" xmi.id="1058" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="3310" linecolour="none" y="1500" instancename="" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1058" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <UML:FloatingTextWidget usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="3280" linecolour="none" y="2450" instancename="" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1058" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="733" widgetaid="226" xmi.id="1059" >
+ <linepath>
+ <startpoint startx="4155" starty="2250" />
+ <endpoint endx="3526" endy="2480" />
+ </linepath>
+ </UML:AssocWidget>
+ <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="2" indexb="1" widgetbid="217" widgetaid="214" xmi.id="1263" >
+ <linepath>
+ <startpoint startx="1460" starty="1396" />
+ <endpoint endx="2590" endy="2330" />
+ <point x="1920" y="1990" />
+ <point x="2150" y="2320" />
+ </linepath>
+ </UML:AssocWidget>
+ </associations>
+ </diagram>
+ </diagrams>
+ <listview>
+ <listitem open="1" type="800" id="-1" label="Views" >
+ <listitem open="1" type="801" id="-1" label="Logical View" >
+ <listitem open="0" type="803" id="187" label="Lib Paket" />
+ <listitem open="1" type="803" id="192" label="Modul Paket" />
+ <listitem open="0" type="807" id="174" label="class diagram" />
+ <listitem open="0" type="818" id="188" label="Lib.connector" >
+ <listitem open="1" type="813" id="189" label="Publisher" />
+ </listitem>
+ <listitem open="1" type="818" id="186" label="Model.base" >
+ <listitem open="1" type="813" id="194" label="Modifiable" >
+ <listitem open="0" type="815" id="889" label="UnsetModified" />
+ <listitem open="0" type="815" id="892" label="WasModified" />
+ <listitem open="0" type="815" id="891" label="__init__" />
+ <listitem open="0" type="815" id="890" label="changed" />
+ </listitem>
+ <listitem open="1" type="813" id="195" label="TitledObject" >
+ <listitem open="0" type="815" id="921" label="SetTitle" />
+ <listitem open="0" type="815" id="920" label="Title" />
+ <listitem open="0" type="815" id="919" label="__init__" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="280" label="Model.classgen" >
+ <listitem open="1" type="813" id="281" label="CustomRamp" />
+ <listitem open="1" type="813" id="282" label="FixedRamp" />
+ <listitem open="1" type="813" id="283" label="HotToColdRamp" />
+ <listitem open="1" type="813" id="284" label="MonochromaticRamp" />
+ </listitem>
+ <listitem open="1" type="818" id="207" label="Model.classification" >
+ <listitem open="1" type="813" id="208" label="ClassGroup" >
+ <listitem open="0" type="815" id="1185" label="GetDisplayText" />
+ <listitem open="0" type="815" id="1186" label="GetLabel" />
+ <listitem open="0" type="815" id="1187" label="GetProperties" />
+ <listitem open="0" type="815" id="1189" label="IsVisible" />
+ <listitem open="0" type="815" id="1190" label="Matches" />
+ <listitem open="0" type="815" id="1193" label="SetLabel" />
+ <listitem open="0" type="815" id="1194" label="SetProperties" />
+ <listitem open="0" type="815" id="1195" label="SetVisible" />
+ <listitem open="0" type="815" id="1184" label="__eq__" />
+ <listitem open="0" type="815" id="1188" label="__init__" />
+ <listitem open="0" type="815" id="1191" label="__ne__" />
+ <listitem open="0" type="815" id="1192" label="__repr__" />
+ </listitem>
+ <listitem open="1" type="813" id="209" label="ClassGroupDefault" >
+ <listitem open="0" type="815" id="1199" label="GetDisplayText" />
+ <listitem open="0" type="815" id="1201" label="Matches" />
+ <listitem open="0" type="815" id="1196" label="__copy__" />
+ <listitem open="0" type="815" id="1197" label="__deepcopy__" />
+ <listitem open="0" type="815" id="1198" label="__eq__" />
+ <listitem open="0" type="815" id="1200" label="__init__" />
+ <listitem open="0" type="815" id="1202" label="__repr__" />
+ </listitem>
+ <listitem open="1" type="813" id="210" label="ClassGroupMap" />
+ <listitem open="1" type="813" id="211" label="ClassGroupProperties" >
+ <listitem open="0" type="815" id="1244" label="GetFill" />
+ <listitem open="0" type="815" id="1245" label="GetLineColor" />
+ <listitem open="0" type="815" id="1246" label="GetLineWidth" />
+ <listitem open="0" type="815" id="1250" label="SetFill" />
+ <listitem open="0" type="815" id="1251" label="SetLineColor" />
+ <listitem open="0" type="815" id="1252" label="SetLineWidth" />
+ <listitem open="0" type="815" id="1253" label="SetProperties" />
+ <listitem open="0" type="815" id="1241" label="__copy__" />
+ <listitem open="0" type="815" id="1242" label="__deepcopy__" />
+ <listitem open="0" type="815" id="1243" label="__eq__" />
+ <listitem open="0" type="815" id="1247" label="__init__" />
+ <listitem open="0" type="815" id="1248" label="__ne__" />
+ <listitem open="0" type="815" id="1249" label="__repr__" />
+ </listitem>
+ <listitem open="1" type="813" id="212" label="ClassGroupRange" >
+ <listitem open="0" type="815" id="1212" label="GetDisplayText" />
+ <listitem open="0" type="815" id="1213" label="GetMax" />
+ <listitem open="0" type="815" id="1214" label="GetMin" />
+ <listitem open="0" type="815" id="1215" label="GetRange" />
+ <listitem open="0" type="815" id="1216" label="GetRangeTuple" />
+ <listitem open="0" type="815" id="1218" label="Matches" />
+ <listitem open="0" type="815" id="1220" label="SetMax" />
+ <listitem open="0" type="815" id="1221" label="SetMin" />
+ <listitem open="0" type="815" id="1222" label="SetRange" />
+ <listitem open="0" type="815" id="1209" label="__copy__" />
+ <listitem open="0" type="815" id="1210" label="__deepcopy__" />
+ <listitem open="0" type="815" id="1211" label="__eq__" />
+ <listitem open="0" type="815" id="1217" label="__init__" />
+ <listitem open="0" type="815" id="1219" label="__repr__" />
+ </listitem>
+ <listitem open="1" type="813" id="213" label="ClassGroupSingleton" >
+ <listitem open="0" type="815" id="1235" label="GetDisplayText" />
+ <listitem open="0" type="815" id="1236" label="GetValue" />
+ <listitem open="0" type="815" id="1238" label="Matches" />
+ <listitem open="0" type="815" id="1240" label="SetValue" />
+ <listitem open="0" type="815" id="1232" label="__copy__" />
+ <listitem open="0" type="815" id="1233" label="__deepcopy__" />
+ <listitem open="0" type="815" id="1234" label="__eq__" />
+ <listitem open="0" type="815" id="1237" label="__init__" />
+ <listitem open="0" type="815" id="1239" label="__repr__" />
+ </listitem>
+ <listitem open="1" type="813" id="215" label="ClassIterator" >
+ <listitem open="0" type="815" id="1181" label="__init__" />
+ <listitem open="0" type="815" id="1182" label="__iter__" />
+ <listitem open="0" type="815" id="1183" label="next" />
+ </listitem>
+ <listitem open="1" type="813" id="214" label="Classification" >
+ <listitem open="0" type="815" id="1154" label="AppendGroup" />
+ <listitem open="0" type="815" id="1160" label="FindGroup" />
+ <listitem open="0" type="815" id="1162" label="GetDefaultFill" />
+ <listitem open="0" type="815" id="1163" label="GetDefaultGroup" />
+ <listitem open="0" type="815" id="1164" label="GetDefaultLineColor" />
+ <listitem open="0" type="815" id="1165" label="GetDefaultLineWidth" />
+ <listitem open="0" type="815" id="1166" label="GetGroup" />
+ <listitem open="0" type="815" id="1167" label="GetNumGroups" />
+ <listitem open="0" type="815" id="1168" label="GetProperties" />
+ <listitem open="0" type="815" id="1170" label="InsertGroup" />
+ <listitem open="0" type="815" id="1172" label="RemoveGroup" />
+ <listitem open="0" type="815" id="1173" label="ReplaceGroup" />
+ <listitem open="0" type="815" id="1175" label="SetDefaultFill" />
+ <listitem open="0" type="815" id="1177" label="SetDefaultGroup" />
+ <listitem open="0" type="815" id="1178" label="SetDefaultLineColor" />
+ <listitem open="0" type="815" id="1179" label="SetDefaultLineWidth" />
+ <listitem open="0" type="815" id="1180" label="TreeInfo" />
+ <listitem open="0" type="815" id="1174" label="__SendNotification" />
+ <listitem open="0" type="815" id="1159" label="__deepcopy__" />
+ <listitem open="0" type="815" id="1161" label="__getattr__" />
+ <listitem open="0" type="815" id="1169" label="__init__" />
+ <listitem open="0" type="815" id="1171" label="__iter__" />
+ <listitem open="0" type="815" id="1157" label="_clear_compiled_classification" />
+ <listitem open="0" type="815" id="1158" label="_compile_classification" />
+ <listitem open="0" type="815" id="1155" label="build_color_item" />
+ <listitem open="0" type="815" id="1156" label="build_item" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="216" label="Model.color" >
+ <listitem open="1" type="813" id="217" label="Color" >
+ <listitem open="0" type="815" id="1258" label="__eq__" />
+ <listitem open="0" type="815" id="1260" label="__init__" />
+ <listitem open="0" type="815" id="1261" label="__ne__" />
+ <listitem open="0" type="815" id="1262" label="__repr__" />
+ <listitem open="0" type="815" id="1259" label="hex" />
+ </listitem>
+ <listitem open="1" type="813" id="218" label="_Transparent" >
+ <listitem open="0" type="815" id="1254" label="__eq__" />
+ <listitem open="0" type="815" id="1256" label="__ne__" />
+ <listitem open="0" type="815" id="1257" label="__repr__" />
+ <listitem open="0" type="815" id="1255" label="hex" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="264" label="Model.data" >
+ <listitem open="1" type="813" id="265" label="DerivedShapeStore" />
+ <listitem open="1" type="813" id="268" label="ShapeTable" />
+ <listitem open="1" type="813" id="266" label="ShapefileShape" />
+ <listitem open="1" type="813" id="267" label="ShapefileStore" />
+ </listitem>
+ <listitem open="1" type="818" id="219" label="Model.extension" >
+ <listitem open="1" type="813" id="220" label="Extension" >
+ <listitem open="0" type="815" id="1143" label="AddObject" />
+ <listitem open="0" type="815" id="1144" label="Destroy" />
+ <listitem open="0" type="815" id="1145" label="FindObject" />
+ <listitem open="0" type="815" id="1147" label="HasObjects" />
+ <listitem open="0" type="815" id="1149" label="Objects" />
+ <listitem open="0" type="815" id="1150" label="RemoveObject" />
+ <listitem open="0" type="815" id="1151" label="TreeInfo" />
+ <listitem open="0" type="815" id="1152" label="UnsetModified" />
+ <listitem open="0" type="815" id="1153" label="WasModified" />
+ <listitem open="0" type="815" id="1148" label="__init__" />
+ <listitem open="0" type="815" id="1146" label="forward" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="198" label="Model.label" >
+ <listitem open="1" type="813" id="199" label="Label" >
+ <listitem open="0" type="815" id="928" label="__init__" />
+ </listitem>
+ <listitem open="1" type="813" id="200" label="LabelLayer" >
+ <listitem open="0" type="815" id="923" label="AddLabel" />
+ <listitem open="0" type="815" id="924" label="ClearLabels" />
+ <listitem open="0" type="815" id="926" label="Labels" />
+ <listitem open="0" type="815" id="927" label="RemoveLabels" />
+ <listitem open="0" type="815" id="925" label="__init__" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="224" label="Model.layer" >
+ <listitem open="1" type="813" id="225" label="BaseLayer" >
+ <listitem open="0" type="815" id="931" label="GetProjection" />
+ <listitem open="0" type="815" id="932" label="HasClassification" />
+ <listitem open="0" type="815" id="933" label="HasShapes" />
+ <listitem open="0" type="815" id="935" label="SetProjection" />
+ <listitem open="0" type="815" id="936" label="SetVisible" />
+ <listitem open="0" type="815" id="937" label="Visible" />
+ <listitem open="0" type="815" id="934" label="__init__" />
+ </listitem>
+ <listitem open="1" type="813" id="226" label="Layer" >
+ <listitem open="0" type="815" id="943" label="BoundingBox" />
+ <listitem open="0" type="815" id="945" label="ClipBoundingBox" />
+ <listitem open="0" type="815" id="946" label="Destroy" />
+ <listitem open="0" type="815" id="948" label="GetClassification" />
+ <listitem open="0" type="815" id="947" label="GetClassificationColumn" />
+ <listitem open="0" type="815" id="949" label="GetFieldType" />
+ <listitem open="0" type="815" id="950" label="HasClassification" />
+ <listitem open="0" type="815" id="951" label="HasShapes" />
+ <listitem open="0" type="815" id="953" label="LatLongBoundingBox" />
+ <listitem open="0" type="815" id="954" label="NumShapes" />
+ <listitem open="0" type="815" id="956" label="SetClassification" />
+ <listitem open="0" type="815" id="955" label="SetClassificationColumn" />
+ <listitem open="0" type="815" id="957" label="SetShapeStore" />
+ <listitem open="0" type="815" id="962" label="ShapeStore" />
+ <listitem open="0" type="815" id="963" label="ShapeType" />
+ <listitem open="0" type="815" id="959" label="Shapes" />
+ <listitem open="0" type="815" id="958" label="ShapesBoundingBox" />
+ <listitem open="0" type="815" id="960" label="ShapesInRegion" />
+ <listitem open="0" type="815" id="964" label="TreeInfo" />
+ <listitem open="0" type="815" id="952" label="__init__" />
+ <listitem open="0" type="815" id="944" label="_classification_changed" />
+ </listitem>
+ <listitem open="1" type="813" id="227" label="RasterLayer" >
+ <listitem open="0" type="815" id="938" label="BoundingBox" />
+ <listitem open="0" type="815" id="939" label="GetImageFilename" />
+ <listitem open="0" type="815" id="941" label="LatLongBox" />
+ <listitem open="0" type="815" id="942" label="TreeInfo" />
+ <listitem open="0" type="815" id="940" label="__init__" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="269" label="Model.load" >
+ <listitem open="1" type="813" id="270" label="AttrDesc" />
+ <listitem open="1" type="813" id="271" label="LoadCancelled" />
+ <listitem open="1" type="813" id="272" label="LoadError" />
+ <listitem open="1" type="813" id="273" label="SessionLoader" />
+ </listitem>
+ <listitem open="1" type="818" id="232" label="Model.map" >
+ <listitem open="1" type="813" id="233" label="Map" >
+ <listitem open="0" type="815" id="1060" label="AddLayer" />
+ <listitem open="0" type="815" id="1061" label="BoundingBox" />
+ <listitem open="0" type="815" id="1062" label="CanRemoveLayer" />
+ <listitem open="0" type="815" id="1063" label="ClearLayers" />
+ <listitem open="0" type="815" id="1064" label="Destroy" />
+ <listitem open="0" type="815" id="1066" label="GetProjection" />
+ <listitem open="0" type="815" id="1067" label="HasLayers" />
+ <listitem open="0" type="815" id="1069" label="LabelLayer" />
+ <listitem open="0" type="815" id="1070" label="Layers" />
+ <listitem open="0" type="815" id="1071" label="LowerLayer" />
+ <listitem open="0" type="815" id="1072" label="MoveLayerToBottom" />
+ <listitem open="0" type="815" id="1073" label="MoveLayerToTop" />
+ <listitem open="0" type="815" id="1074" label="ProjectedBoundingBox" />
+ <listitem open="0" type="815" id="1075" label="RaiseLayer" />
+ <listitem open="0" type="815" id="1076" label="RemoveLayer" />
+ <listitem open="0" type="815" id="1077" label="SetProjection" />
+ <listitem open="0" type="815" id="1079" label="TreeInfo" />
+ <listitem open="0" type="815" id="1080" label="UnsetModified" />
+ <listitem open="0" type="815" id="1082" label="WasModified" />
+ <listitem open="0" type="815" id="1068" label="__init__" />
+ <listitem open="0" type="815" id="1065" label="forward" />
+ <listitem open="0" type="815" id="1078" label="subscribe_layer_channels" />
+ <listitem open="0" type="815" id="1081" label="unsubscribe_layer_channels" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="196" label="Model.messages" />
+ <listitem open="0" type="818" id="285" label="Model.postgisdb" >
+ <listitem open="1" type="813" id="286" label="ConnectionError" />
+ <listitem open="1" type="813" id="287" label="PostGISColumn" />
+ <listitem open="1" type="813" id="288" label="PostGISConnection" />
+ <listitem open="1" type="813" id="289" label="PostGISShape" />
+ <listitem open="1" type="813" id="825" label="PostGISShapeStore" />
+ <listitem open="1" type="813" id="291" label="PostGISTable" />
+ </listitem>
+ <listitem open="1" type="818" id="236" label="Model.proj" >
+ <listitem open="1" type="813" id="237" label="BaseProjection" />
+ <listitem open="1" type="813" id="238" label="ProjFile" />
+ <listitem open="1" type="813" id="733" label="Projection" >
+ <listitem open="0" type="815" id="991" label="EPSGCode" />
+ <listitem open="0" type="815" id="992" label="ForwardBBox" />
+ <listitem open="0" type="815" id="993" label="GetAllParameters" />
+ <listitem open="0" type="815" id="994" label="GetName" />
+ <listitem open="0" type="815" id="995" label="GetParameter" />
+ <listitem open="0" type="815" id="996" label="GetProjectedUnits" />
+ <listitem open="0" type="815" id="998" label="InverseBBox" />
+ <listitem open="0" type="815" id="999" label="Label" />
+ <listitem open="0" type="815" id="997" label="__init__" />
+ <listitem open="0" type="815" id="1000" label="__repr__" />
+ <listitem open="0" type="815" id="1001" label="_transform_bbox" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="261" label="Model.range" >
+ <listitem open="1" type="813" id="262" label="Range" >
+ <listitem open="0" type="815" id="1226" label="GetRange" />
+ <listitem open="0" type="815" id="1229" label="_SetRange" />
+ <listitem open="0" type="815" id="1223" label="__contains__" />
+ <listitem open="0" type="815" id="1224" label="__eq__" />
+ <listitem open="0" type="815" id="1227" label="__init__" />
+ <listitem open="0" type="815" id="1228" label="__ne__" />
+ <listitem open="0" type="815" id="1231" label="__str__" />
+ <listitem open="0" type="815" id="1225" label="_float2string" />
+ <listitem open="0" type="815" id="1230" label="string" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="292" label="Model.resource" >
+ <listitem open="1" type="813" id="293" label="ProjFileReader" />
+ <listitem open="1" type="813" id="294" label="ProjFileSaver" />
+ </listitem>
+ <listitem open="0" type="818" id="295" label="Model.save" >
+ <listitem open="1" type="813" id="296" label="SessionSaver" />
+ </listitem>
+ <listitem open="1" type="818" id="297" label="Model.scalebar" />
+ <listitem open="1" type="818" id="239" label="Model.session" >
+ <listitem open="1" type="813" id="240" label="AutoRemoveDir" />
+ <listitem open="1" type="813" id="241" label="AutoRemoveFile" />
+ <listitem open="1" type="813" id="242" label="Session" >
+ <listitem open="0" type="815" id="1083" label="AddDBConnection" />
+ <listitem open="0" type="815" id="1084" label="AddExtension" />
+ <listitem open="0" type="815" id="1085" label="AddMap" />
+ <listitem open="0" type="815" id="1086" label="AddShapeStore" />
+ <listitem open="0" type="815" id="1088" label="AddTable" />
+ <listitem open="0" type="815" id="1089" label="CanRemoveDBConnection" />
+ <listitem open="0" type="815" id="1093" label="DBConnections" />
+ <listitem open="0" type="815" id="1092" label="DataContainers" />
+ <listitem open="0" type="815" id="1094" label="Destroy" />
+ <listitem open="0" type="815" id="1095" label="Extensions" />
+ <listitem open="0" type="815" id="1097" label="HasDBConnections" />
+ <listitem open="0" type="815" id="1098" label="HasExtensions" />
+ <listitem open="0" type="815" id="1099" label="HasMaps" />
+ <listitem open="0" type="815" id="1101" label="Maps" />
+ <listitem open="0" type="815" id="1102" label="OpenDBShapeStore" />
+ <listitem open="0" type="815" id="1103" label="OpenShapefile" />
+ <listitem open="0" type="815" id="1104" label="OpenTableFile" />
+ <listitem open="0" type="815" id="1105" label="RemoveDBConnection" />
+ <listitem open="0" type="815" id="1106" label="RemoveMap" />
+ <listitem open="0" type="815" id="1107" label="RemoveTable" />
+ <listitem open="0" type="815" id="1108" label="SetFilename" />
+ <listitem open="0" type="815" id="1109" label="ShapeStores" />
+ <listitem open="0" type="815" id="1110" label="Tables" />
+ <listitem open="0" type="815" id="1112" label="TransientDB" />
+ <listitem open="0" type="815" id="1113" label="TreeInfo" />
+ <listitem open="0" type="815" id="1114" label="UnreferencedTables" />
+ <listitem open="0" type="815" id="1115" label="UnsetModified" />
+ <listitem open="0" type="815" id="1116" label="WasModified" />
+ <listitem open="0" type="815" id="1100" label="__init__" />
+ <listitem open="0" type="815" id="1087" label="_add_shapestore" />
+ <listitem open="0" type="815" id="1091" label="_clean_weak_store_refs" />
+ <listitem open="0" type="815" id="1090" label="changed" />
+ <listitem open="0" type="815" id="1096" label="forward" />
+ <listitem open="0" type="815" id="1111" label="temp_directory" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="298" label="Model.table" >
+ <listitem open="1" type="813" id="299" label="DBFColumn" />
+ <listitem open="1" type="813" id="300" label="DBFTable" />
+ <listitem open="1" type="813" id="301" label="MemoryColumn" />
+ <listitem open="1" type="813" id="302" label="MemoryTable" />
+ </listitem>
+ <listitem open="0" type="818" id="303" label="Model.transientdb" >
+ <listitem open="1" type="813" id="304" label="AutoTransientTable" />
+ <listitem open="1" type="813" id="305" label="ColiumnReference" />
+ <listitem open="1" type="813" id="306" label="TransientDatabase" />
+ <listitem open="1" type="813" id="307" label="TransientJoinedTable" />
+ <listitem open="1" type="813" id="309" label="TransientTable" />
+ <listitem open="1" type="813" id="308" label="TransientTableBase" />
+ </listitem>
+ <listitem open="1" type="818" id="310" label="Model.wellknowntext" />
+ <listitem open="0" type="818" id="311" label="Model.xmlreader" >
+ <listitem open="1" type="813" id="313" label="XMLReader" />
+ </listitem>
+ <listitem open="0" type="818" id="312" label="Model.xmlwriter" >
+ <listitem open="1" type="813" id="314" label="XMLWriter" />
+ </listitem>
+ <listitem open="0" type="830" id="-1" label="Datatypes" >
+ <listitem open="1" type="829" id="177" label="bool" />
+ <listitem open="1" type="829" id="176" label="char" />
+ <listitem open="1" type="829" id="179" label="double" />
+ <listitem open="1" type="829" id="178" label="float" />
+ <listitem open="1" type="829" id="175" label="int" />
+ <listitem open="1" type="829" id="180" label="long" />
+ <listitem open="1" type="829" id="181" label="short" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="802" id="-1" label="Use Case View" />
+ <listitem open="1" type="821" id="-1" label="Component View" />
+ <listitem open="1" type="827" id="-1" label="Deployment View" />
+ </listitem>
+ </listview>
+ <codegeneration/>
+ </XMI.content>
+</XMI>
Added: packages/thuban/branches/upstream/current/Doc/ThubanModel.xmi
===================================================================
--- packages/thuban/branches/upstream/current/Doc/ThubanModel.xmi 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/ThubanModel.xmi 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1515 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<XMI xmlns:UML="org.omg/standards/UML" verified="false" timestamp="" xmi.version="1.2" >
+ <XMI.header>
+ <XMI.documentation>
+ <XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
+ <XMI.exporterVersion>1.2.90</XMI.exporterVersion>
+ <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
+ </XMI.documentation>
+ <XMI.model xmi.name="ThubanModel" href="./ThubanModel.xmi" />
+ <XMI.metamodel xmi.name="UML" href="UML.xml" xmi.version="1.3" />
+ </XMI.header>
+ <XMI.content>
+ <UML:Model>
+ <UML:Stereotype visibility="public" xmi.id="1358" name="datatype" />
+ <UML:Stereotype visibility="public" xmi.id="1365" name="class" />
+ <UML:Stereotype visibility="public" xmi.id="1366" name="Lib" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="175" name="int" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="176" name="char" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="177" name="bool" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="178" name="float" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="179" name="double" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="180" name="long" />
+ <UML:DataType stereotype="1358" visibility="public" xmi.id="181" name="short" />
+ <UML:Package visibility="public" xmi.id="186" name="Model.base" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="194" name="Modifiable" >
+ <UML:Operation visibility="public" xmi.id="889" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="890" type="void" name="changed" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="string" name="channel" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="*.args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="891" type="void" name="__init__" />
+ <UML:Operation visibility="public" xmi.id="892" type="bool" name="WasModified" />
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="195" name="TitledObject" >
+ <UML:Operation visibility="public" xmi.id="919" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="920" type="string" name="Title" />
+ <UML:Operation visibility="public" xmi.id="921" type="void" name="SetTitle" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package stereotype="1366" visibility="public" xmi.id="188" name="Lib.connector" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="189" name="Publisher" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="196" name="Model.messages" />
+ <UML:Package visibility="public" xmi.id="198" name="Model.label" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="199" name="Label" >
+ <UML:Operation visibility="public" xmi.id="928" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="x" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="y" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="string" name="text" />
+ <UML:Parameter visibility="public" xmi.id="4" value="" type="string" name="halign" />
+ <UML:Parameter visibility="public" xmi.id="5" value="" type="string" name="valign" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="200" name="LabelLayer" >
+ <UML:Operation visibility="public" xmi.id="923" type="void" name="AddLabel" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="x" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="y" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="string" name="text" />
+ <UML:Parameter visibility="public" xmi.id="4" value="left" type="string" name="halign" />
+ <UML:Parameter visibility="public" xmi.id="5" value="center" type="string" name="valign" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="924" type="void" name="ClearLabels" />
+ <UML:Operation visibility="public" xmi.id="925" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="926" type="void" name="Labels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Label" name="labels" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="927" type="void" name="RemoveLabels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="207" name="Model.classification" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="208" name="ClassGroup" >
+ <UML:Operation visibility="public" xmi.id="1184" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1185" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1186" type="Label" name="GetLabel" />
+ <UML:Operation visibility="public" xmi.id="1187" type="ClassGroupProperties" name="GetProperties" />
+ <UML:Operation visibility="public" xmi.id="1188" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1189" type="bool" name="IsVisible" />
+ <UML:Operation visibility="public" xmi.id="1190" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1191" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1192" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1193" type="void" name="SetLabel" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="label" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1194" type="void" name="SetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="prop" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1195" type="void" name="SetVisible" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="bool" name="visible" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="209" name="ClassGroupDefault" >
+ <UML:Operation visibility="public" xmi.id="1196" type="ClassGroupDefault" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1197" type="ClassGroupDefault" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="memo" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1198" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1199" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1200" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="2" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1201" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1202" type="string" name="__repr__" />
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="210" name="ClassGroupMap" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="211" name="ClassGroupProperties" >
+ <UML:Operation visibility="public" xmi.id="1241" type="ClassGroupProperties" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1242" type="ClassGroupProperties" name="__deepcopy__" />
+ <UML:Operation visibility="public" xmi.id="1243" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1244" type="Color" name="GetFill" />
+ <UML:Operation visibility="public" xmi.id="1245" type="Color" name="GetLineColor" />
+ <UML:Operation visibility="public" xmi.id="1246" type="int" name="GetLineWidth" />
+ <UML:Operation visibility="public" xmi.id="1247" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="ClassGroupProperties" name="props" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1248" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1249" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1250" type="void" name="SetFill" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="fill" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1251" type="void" name="SetLineColor" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1252" type="void" name="SetLineWidth" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="lineWidth" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1253" type="void" name="SetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroupProperties" name="props" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="212" name="ClassGroupRange" >
+ <UML:Operation visibility="public" xmi.id="1209" type="ClassGroupRange" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1210" type="ClassGroupRange" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="mono" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1211" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClasGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1212" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1213" type="int" name="GetMax" />
+ <UML:Operation visibility="public" xmi.id="1214" type="int" name="GetMin" />
+ <UML:Operation visibility="public" xmi.id="1215" type="string" name="GetRange" />
+ <UML:Operation visibility="public" xmi.id="1216" type="string" name="GetRangeTuple" />
+ <UML:Operation visibility="public" xmi.id="1217" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="(0, 1)" type="int2 or ClassGroupRange" name="_range" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1218" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1219" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1220" type="void" name="SetMax" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="max" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1221" type="void" name="SetMin" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="min" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1222" type="void" name="SetRange" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int2 or Range" name="_range" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="213" name="ClassGroupSingleton" >
+ <UML:Operation visibility="public" xmi.id="1232" type="ClassGroupSingleton" name="__copy__" />
+ <UML:Operation visibility="public" xmi.id="1233" type="ClassGroupSingleton" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="mono" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1234" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1235" type="string" name="GetDisplayText" />
+ <UML:Operation visibility="public" xmi.id="1236" type="float" name="GetValue" />
+ <UML:Operation visibility="public" xmi.id="1237" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="0" type="float" name="value" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="ClassGroupProperties" name="props" />
+ <UML:Parameter visibility="public" xmi.id="3" value=" " type="string" name="label" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1238" type="bool" name="Matches" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1239" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1240" type="void" name="SetValue" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="214" name="Classification" >
+ <UML:Operation visibility="public" xmi.id="1154" type="void" name="AppendGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="item" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="1155" type="string" name="build_color_item" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="private" xmi.id="1156" type="string" name="build_item" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="string" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1157" type="void" name="_clear_compiled_classification" />
+ <UML:Operation visibility="public" xmi.id="1158" type="void" name="_compile_classification" />
+ <UML:Operation visibility="public" xmi.id="1159" type="Classification" name="__deepcopy__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="memo" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1160" type="ClassGroup" name="FindGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1161" type="void" name="__getattr__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="attr" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1162" type="Color" name="GetDefaultFill" />
+ <UML:Operation visibility="public" xmi.id="1163" type="ClassGroupDefault" name="GetDefaultGroup" />
+ <UML:Operation visibility="public" xmi.id="1164" type="Color" name="GetDefaultLineColor" />
+ <UML:Operation visibility="public" xmi.id="1165" type="int" name="GetDefaultLineWidth" />
+ <UML:Operation visibility="public" xmi.id="1166" type="ClassGroup" name="GetGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1167" type="int" name="GetNumGroups" />
+ <UML:Operation visibility="public" xmi.id="1168" type="ClassGroupProperties" name="GetProperties" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1169" type="void" name="__init__" />
+ <UML:Operation visibility="public" xmi.id="1170" type="void" name="InsertGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1171" type="ClassIterator" name="__iter__" />
+ <UML:Operation visibility="public" xmi.id="1172" type="void" name="RemoveGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1173" type="void" name="ReplaceGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1174" type="void" name="__SendNotification" />
+ <UML:Operation visibility="public" xmi.id="1175" type="void" name="SetDefaultFill" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="fill" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1177" type="void" name="SetDefaultGroup" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup" name="group" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1178" type="void" name="SetDefaultLineColor" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="color" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1179" type="void" name="SetDefaultLineWidth" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="lineWidth" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1180" type="string[]" name="TreeInfo" />
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="215" name="ClassIterator" >
+ <UML:Operation visibility="public" xmi.id="1181" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ClassGroup[]" name="data" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1182" type="ClassIterator" name="__iter__" />
+ <UML:Operation visibility="public" xmi.id="1183" type="ClassGroup" name="next" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="216" name="Model.color" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="217" name="Color" >
+ <UML:Operation visibility="public" xmi.id="1258" type="void" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1259" type="string" name="hex" />
+ <UML:Operation visibility="public" xmi.id="1260" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="red" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int" name="green" />
+ <UML:Parameter visibility="public" xmi.id="3" value="" type="int" name="blue" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1261" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Color" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1262" type="string" name="__repr__" />
+ </UML:Class>
+ <UML:Class stereotype="1365" comment="An object which represents no color." visibility="private" xmi.id="218" name="_Transparent" >
+ <UML:Operation visibility="public" xmi.id="1254" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Object" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1255" type="string" name="hex" />
+ <UML:Operation visibility="public" xmi.id="1256" type="bool" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Object" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1257" type="string" name="__repr__" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="219" name="Model.extension" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="220" name="Extension" >
+ <UML:Operation visibility="public" xmi.id="1143" type="void" name="AddObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ObjectfromExtension" name="object" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1144" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1145" type="ObjectfromExtension" name="FindObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1146" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*.args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1147" type="bool" name="HasObjects" />
+ <UML:Operation visibility="public" xmi.id="1148" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1149" type="ObjectfromExtension[]" name="Objects" />
+ <UML:Operation visibility="public" xmi.id="1150" type="void" name="RemoveObject" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ObjectfromExtension" name="object" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1151" type="string[]" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1152" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1153" type="int" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="224" name="Model.layer" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="225" name="BaseLayer" >
+ <UML:Operation visibility="public" xmi.id="931" type="Projection" name="GetProjection" />
+ <UML:Operation visibility="public" xmi.id="932" type="bool" name="HasClassification" />
+ <UML:Operation visibility="public" xmi.id="933" type="bool" name="HasShapes" />
+ <UML:Operation visibility="public" xmi.id="934" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="True" type="bool" name="visible" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="935" type="void" name="SetProjection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="936" type="void" name="SetVisible" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="937" type="bool" name="Visible" />
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="226" name="Layer" >
+ <UML:Operation visibility="public" xmi.id="943" type="tuple(int,int,int,int)" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="944" type="void" name="_classification_changed" />
+ <UML:Operation visibility="public" xmi.id="945" type="tuple(int,int,int,int)" name="ClipBoundingBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(int,int,int,int)" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="946" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="947" type="string" name="GetClassificationColumn" />
+ <UML:Operation visibility="public" xmi.id="948" type="Classification" name="GetClassification" />
+ <UML:Operation visibility="public" xmi.id="949" type="Column.type" name="GetFieldType" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="fieldName" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="950" type="bool" name="HasClassification" />
+ <UML:Operation visibility="public" xmi.id="951" type="bool" name="HasShapes" />
+ <UML:Operation visibility="public" xmi.id="952" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="Shape data" name="data" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ <UML:Parameter visibility="public" xmi.id="4" value="Transparent" type="Color" name="fill" />
+ <UML:Parameter visibility="public" xmi.id="5" value="Black" type="Color" name="stroke" />
+ <UML:Parameter visibility="public" xmi.id="6" value="1" type="int" name="lineWidth" />
+ <UML:Parameter visibility="public" xmi.id="7" value="True" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="953" type="bbox" name="LatLongBoundingBox" />
+ <UML:Operation visibility="public" xmi.id="954" type="int" name="NumShapes" />
+ <UML:Operation visibility="public" xmi.id="955" type="void" name="SetClassificationColumn" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="column" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="956" type="void" name="SetClassification" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Classification" name="clazz" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="957" type="void" name="SetShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="shapestore" name="store" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="958" type="tuple(int,int,int,int)" name="ShapesBoundingBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="shapes" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="959" type="Shape" name="Shapes" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="index" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="960" type="Shapes" name="ShapesInRegion" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(int,int,int,int)" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="962" type="shapestore" name="ShapeStore" />
+ <UML:Operation visibility="public" xmi.id="963" type="constanten" name="ShapeType" />
+ <UML:Operation visibility="public" xmi.id="964" type="string()" name="TreeInfo" />
+ </UML:Class>
+ <UML:Class stereotype="1365" visibility="public" xmi.id="227" name="RasterLayer" >
+ <UML:Operation visibility="public" xmi.id="938" type="tuple(int,int,int,int))" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="939" type="string" name="GetImageFilename" />
+ <UML:Operation visibility="public" xmi.id="940" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="string" name="filename" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="Projection" name="projection" />
+ <UML:Parameter visibility="public" xmi.id="4" value="True" type="bool" name="visible" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="941" type="tuple(int,int,int,int)" name="LatLongBox" />
+ <UML:Operation visibility="public" xmi.id="942" type="tuple(string, array(string))" name="TreeInfo" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="232" name="Model.map" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="233" name="Map" >
+ <UML:Operation visibility="public" xmi.id="1060" type="void" name="AddLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1061" type="int4" name="BoundingBox" />
+ <UML:Operation visibility="public" xmi.id="1062" type="int" name="CanRemoveLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1063" type="void" name="ClearLayers" />
+ <UML:Operation visibility="public" xmi.id="1064" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1065" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1066" type="Projection" name="GetProjection" />
+ <UML:Operation visibility="public" xmi.id="1067" type="bool" name="HasLayers" />
+ <UML:Operation visibility="public" xmi.id="1068" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1069" type="LabelLayer" name="LabelLayer" />
+ <UML:Operation visibility="public" xmi.id="1070" type="Layer[]" name="Layers" />
+ <UML:Operation visibility="public" xmi.id="1071" type="void" name="LowerLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1072" type="void" name="MoveLayerToBottom" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1073" type="void" name="MoveLayerToTop" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1074" type="int4" name="ProjectedBoundingBox" />
+ <UML:Operation visibility="public" xmi.id="1075" type="void" name="RaiseLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1076" type="void" name="RemoveLayer" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1077" type="void" name="SetProjection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Projection" name="projection" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1078" type="void" name="subscribe_layer_channels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1079" type="void" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1080" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1081" type="void" name="unsubscribe_layer_channels" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Layer" name="layer" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1082" type="string()" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="236" name="Model.proj" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="237" name="BaseProjection" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="238" name="ProjFile" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="733" name="Projection" >
+ <UML:Operation visibility="public" xmi.id="991" type="string" name="EPSGCode" />
+ <UML:Operation visibility="public" xmi.id="992" type="int()" name="ForwardBBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int()" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="993" type="string[]" name="GetAllParameters" />
+ <UML:Operation visibility="public" xmi.id="994" type="string" name="GetName" />
+ <UML:Operation visibility="public" xmi.id="995" type="string" name="GetParameter" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="param" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="996" type="int" name="GetProjectedUnits" />
+ <UML:Operation visibility="public" xmi.id="997" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="stinr[]" name="params" />
+ <UML:Parameter visibility="public" xmi.id="2" value="None" type="string" name="name" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="string" name="epsg" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="998" type="int()" name="InverseBBox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int()" name="bbox" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="999" type="string" name="Label" />
+ <UML:Operation visibility="public" xmi.id="1000" type="string" name="__repr__" />
+ <UML:Operation visibility="public" xmi.id="1001" type="int(4)" name="_transform_bbox" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Trafo" name="trafo" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="int(4)" name="bbox" />
+ </UML:Operation>
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="239" name="Model.session" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="240" name="AutoRemoveDir" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="241" name="AutoRemoveFile" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="242" name="Session" >
+ <UML:Operation visibility="public" xmi.id="1083" type="void" name="AddDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1084" type="void" name="AddExtension" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Extension" name="extension" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1085" type="void" name="AddMap" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Map" name="map" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1086" type="void" name="AddShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ShapefileStore" name="shapestore" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1087" type="void" name="_add_shapestore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="ShapefileStore" name="store" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1088" type="void" name="AddTable" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="AutoTransientTable" name="table" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1089" type="int" name="CanRemoveDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1090" type="void" name="changed" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="" name="channel" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1091" type="void" name="_clean_weak_store_refs" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="weakref" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1092" type="data containers" name="DataContainers" />
+ <UML:Operation visibility="public" xmi.id="1093" type="PostGISConnection" name="DBConnections" />
+ <UML:Operation visibility="public" xmi.id="1094" type="void" name="Destroy" />
+ <UML:Operation visibility="public" xmi.id="1095" type="Extension[]" name="Extensions" />
+ <UML:Operation visibility="public" xmi.id="1096" type="void" name="forward" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="" name="*args" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1097" type="int" name="HasDBConnections" />
+ <UML:Operation visibility="public" xmi.id="1098" type="int" name="HasExtensions" />
+ <UML:Operation visibility="public" xmi.id="1099" type="int" name="HasMaps" />
+ <UML:Operation visibility="public" xmi.id="1100" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="title" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1101" type="Map[]" name="Maps" />
+ <UML:Operation visibility="public" xmi.id="1102" type="ShapefileStore" name="OpenDBShapeStore" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="db" />
+ <UML:Parameter visibility="public" xmi.id="2" value="" type="string" name="tablename" />
+ <UML:Parameter visibility="public" xmi.id="3" value="None" type="string" name="id_column" />
+ <UML:Parameter visibility="public" xmi.id="4" value="None" type="string" name="geometry_column" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1103" type="ShapefileStore" name="OpenShapefile" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1104" type="DBFTable" name="OpenTableFile" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1105" type="void" name="RemoveDBConnection" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="PostGISConnection" name="dbconn" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1106" type="void" name="RemoveMap" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Map" name="map" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1107" type="void" name="RemoveTable" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="*Table" name="table" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1108" type="void" name="SetFilename" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="filename" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1109" type="ShapefileStore[]" name="ShapeStores" />
+ <UML:Operation visibility="public" xmi.id="1110" type="*Tables[]" name="Tables" />
+ <UML:Operation visibility="public" xmi.id="1111" type="string" name="temp_directory" />
+ <UML:Operation visibility="public" xmi.id="1112" type="TransientDatabase" name="TransientDB" />
+ <UML:Operation visibility="public" xmi.id="1113" type="string[]" name="TreeInfo" />
+ <UML:Operation visibility="public" xmi.id="1114" type="*Tables[]" name="UnreferencedTables" />
+ <UML:Operation visibility="public" xmi.id="1115" type="void" name="UnsetModified" />
+ <UML:Operation visibility="public" xmi.id="1116" type="int" name="WasModified" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="261" name="Model.range" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="262" name="Range" >
+ <UML:Operation visibility="public" xmi.id="1223" type="bool" name="__contains__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="int" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1224" type="bool" name="__eq__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Range" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1225" type="string" name="_float2string" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="float" name="value" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1226" type="string4" name="GetRange" />
+ <UML:Operation visibility="public" xmi.id="1227" type="void" name="__init__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="None" type="string" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1228" type="void" name="__ne__" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="Range" name="other" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1229" type="void" name="_SetRange" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="string" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1230" type="string" name="string" >
+ <UML:Parameter visibility="public" xmi.id="1" value="" type="tuple(string,int,int,string)" name="range" />
+ </UML:Operation>
+ <UML:Operation visibility="public" xmi.id="1231" type="string" name="__str__" />
+ </UML:Class>
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="264" name="Model.data" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="265" name="DerivedShapeStore" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="266" name="ShapefileShape" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="267" name="ShapefileStore" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="268" name="ShapeTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="269" name="Model.load" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="270" name="AttrDesc" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="271" name="LoadCancelled" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="272" name="LoadError" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="273" name="SessionLoader" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="280" name="Model.classgen" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="281" name="CustomRamp" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="282" name="FixedRamp" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="283" name="HotToColdRamp" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="284" name="MonochromaticRamp" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="285" name="Model.postgisdb" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="286" name="ConnectionError" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="287" name="PostGISColumn" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="288" name="PostGISConnection" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="289" name="PostGISShape" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="291" name="PostGISTable" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="825" name="PostGISShapeStore" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="292" name="Model.resource" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="293" name="ProjFileReader" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="294" name="ProjFileSaver" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="295" name="Model.save" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="296" name="SessionSaver" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="297" name="Model.scalebar" />
+ <UML:Package visibility="public" xmi.id="298" name="Model.table" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="299" name="DBFColumn" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="300" name="DBFTable" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="301" name="MemoryColumn" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="302" name="MemoryTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="303" name="Model.transientdb" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="304" name="AutoTransientTable" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="305" name="ColiumnReference" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="306" name="TransientDatabase" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="307" name="TransientJoinedTable" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="308" name="TransientTableBase" />
+ <UML:Class stereotype="1365" visibility="public" xmi.id="309" name="TransientTable" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="310" name="Model.wellknowntext" />
+ <UML:Package visibility="public" xmi.id="311" name="Model.xmlreader" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="313" name="XMLReader" />
+ </UML:Package>
+ <UML:Package visibility="public" xmi.id="312" name="Model.xmlwriter" >
+ <UML:Class stereotype="1365" visibility="public" xmi.id="314" name="XMLWriter" />
+ </UML:Package>
+ <UML:Association visibility="public" xmi.id="201" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="200" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="202" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="194" />
+ <UML:AssociationEndRole visibility="public" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="203" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="200" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="206" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="194" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="221" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="220" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="222" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="220" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="228" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="225" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="229" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="225" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="230" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="226" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="225" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="231" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="227" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="225" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="234" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="235" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="243" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="242" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="194" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="244" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="242" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="195" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="251" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="210" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="252" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="212" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="253" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="213" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="254" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="214" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="263" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="218" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="316" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="195" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="189" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="318" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="233" />
+ <UML:AssociationEndRole visibility="public" type="233" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="341" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="none" type="227" />
+ <UML:AssociationEndRole visibility="public" isNavigable="true" type="226" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="194" visibility="public" xmi.id="600" parent="189" />
+ <UML:Generalization child="200" visibility="public" xmi.id="602" parent="195" />
+ <UML:Generalization child="200" visibility="public" xmi.id="603" parent="194" />
+ <UML:Association visibility="public" xmi.id="605" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="200" />
+ <UML:AssociationEndRole visibility="public" type="199" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="225" visibility="public" xmi.id="615" parent="195" />
+ <UML:Generalization child="225" visibility="public" xmi.id="616" parent="194" />
+ <UML:Generalization child="220" visibility="public" xmi.id="625" parent="194" />
+ <UML:Generalization child="220" visibility="public" xmi.id="626" parent="195" />
+ <UML:Generalization child="233" visibility="public" xmi.id="645" parent="194" />
+ <UML:Generalization child="233" visibility="public" xmi.id="646" parent="195" />
+ <UML:Generalization child="242" visibility="public" xmi.id="655" parent="194" />
+ <UML:Generalization child="242" visibility="public" xmi.id="656" parent="195" />
+ <UML:Generalization child="227" visibility="public" xmi.id="669" parent="225" />
+ <UML:Generalization child="226" visibility="public" xmi.id="670" parent="225" />
+ <UML:Generalization child="214" visibility="public" xmi.id="679" parent="189" />
+ <UML:Association visibility="public" xmi.id="681" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="214" />
+ <UML:AssociationEndRole visibility="public" type="208" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization child="209" visibility="public" xmi.id="695" parent="208" />
+ <UML:Generalization child="212" visibility="public" xmi.id="705" parent="208" />
+ <UML:Generalization child="213" visibility="public" xmi.id="706" parent="208" />
+ <UML:Association visibility="public" xmi.id="708" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="226" />
+ <UML:AssociationEndRole visibility="public" type="214" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="715" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="208" />
+ <UML:AssociationEndRole visibility="public" type="211" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="716" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="211" />
+ <UML:AssociationEndRole visibility="public" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="721" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="242" />
+ <UML:AssociationEndRole visibility="public" type="233" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="722" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="242" />
+ <UML:AssociationEndRole visibility="public" type="220" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="731" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="233" />
+ <UML:AssociationEndRole visibility="public" type="226" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="732" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="composite" type="233" />
+ <UML:AssociationEndRole visibility="public" type="227" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="816" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="212" />
+ <UML:AssociationEndRole visibility="public" type="262" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1058" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="233" />
+ <UML:AssociationEndRole visibility="public" type="733" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1059" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="226" />
+ <UML:AssociationEndRole visibility="public" type="733" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association visibility="public" xmi.id="1263" >
+ <UML:Association.connection>
+ <UML:AssociationEndRole visibility="public" aggregation="shared" type="214" />
+ <UML:AssociationEndRole visibility="public" type="217" />
+ </UML:Association.connection>
+ </UML:Association>
+ </UML:Model>
+ </XMI.content>
+ <XMI.extensions xmi.extender="umbrello" >
+ <docsettings viewid="174" documentation="" uniqueid="1379" />
+ <diagrams>
+ <diagram snapgrid="1" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="64" showgrid="1" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="5063" snapy="10" showatts="1" xmi.id="174" documentation="" type="402" showops="1" showpackage="0" name="class diagram" localid="30000" showstereotype="0" showscope="1" snapcsgrid="1" font="helvetica,12,-1,0,50,0,0,0,0,0" linecolor="#ff0000" canvasheight="2869" >
+ <widgets>
+ <classwidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="2425" linecolour="#ff0000" y="410" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="120" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="194" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="240" showattsigs="601" usesdiagramusefillcolour="0" x="3090" linecolour="#ff0000" y="410" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="100" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="195" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="1" width="230" showattsigs="601" usesdiagramusefillcolour="1" x="2495" linecolour="none" y="170" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="1" fillcolour="none" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="189" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="helvetica,12,-1,0,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="710" showattsigs="601" usesdiagramusefillcolour="0" x="4325" linecolour="#ff0000" y="1010" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="200" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="580" showattsigs="601" usesdiagramusefillcolour="0" x="4390" linecolour="#ff0000" y="1220" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="60" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="199" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="640" showattsigs="601" usesdiagramusefillcolour="0" x="3660" linecolour="#ff0000" y="1010" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="180" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="225" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="420" showattsigs="601" usesdiagramusefillcolour="0" x="1540" linecolour="#ff0000" y="1015" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="270" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="220" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="1035" linecolour="#ff0000" y="1010" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="580" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="214" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="480" showattsigs="601" usesdiagramusefillcolour="0" x="3160" linecolour="#ff0000" y="1010" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="520" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="233" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="1110" showattsigs="601" usesdiagramusefillcolour="0" x="2005" linecolour="#ff0000" y="1015" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="750" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="242" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="1310" showattsigs="601" usesdiagramusefillcolour="0" x="3505" linecolour="#ff0000" y="1770" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="480" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="226" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="770" showattsigs="601" usesdiagramusefillcolour="0" x="4235" linecolour="#ff0000" y="1530" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="227" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="780" showattsigs="601" usesdiagramusefillcolour="0" x="890" linecolour="#ff0000" y="1855" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="290" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="208" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="780" showattsigs="601" usesdiagramusefillcolour="0" x="1170" linecolour="#ff0000" y="2230" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="180" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="209" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="430" showattsigs="601" usesdiagramusefillcolour="0" x="2385" linecolour="#ff0000" y="2535" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="310" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="211" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="1100" showattsigs="601" usesdiagramusefillcolour="0" x="790" linecolour="#ff0000" y="2515" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="330" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="212" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="910" showattsigs="601" usesdiagramusefillcolour="0" x="2285" linecolour="#ff0000" y="1980" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="220" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="213" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="300" showattsigs="601" usesdiagramusefillcolour="0" x="880" linecolour="#ff0000" y="1700" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="100" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="215" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="380" showattsigs="601" usesdiagramusefillcolour="0" x="2590" linecolour="#ff0000" y="2260" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="140" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="217" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="250" showattsigs="601" usesdiagramusefillcolour="0" x="2835" linecolour="#ff0000" y="2530" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="120" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="218" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="610" showattsigs="601" usesdiagramusefillcolour="0" x="3125" linecolour="#ff0000" y="2485" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="270" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="733" showoperations="1" showpackage="0" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ <classwidget usesdiagramfillcolour="0" width="400" showattsigs="601" usesdiagramusefillcolour="0" x="1950" linecolour="#ff0000" y="2570" showopsigs="601" linewidth="none" usesdiagramlinewidth="1" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="220" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="262" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Bitstream Charter,12,-1,5,75,0,0,0,0,0" />
+ </widgets>
+ <messages/>
+ <associations>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="189" widgetaid="194" xmi.id="600" >
+ <linepath>
+ <startpoint startx="2640" starty="410" />
+ <endpoint endx="2650" endy="210" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="6" indexb="5" widgetbid="195" widgetaid="200" xmi.id="602" >
+ <linepath>
+ <startpoint startx="4800" starty="1010" />
+ <endpoint endx="3290" endy="510" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="6" indexb="5" widgetbid="194" widgetaid="200" xmi.id="603" >
+ <linepath>
+ <startpoint startx="4560" starty="1010" />
+ <endpoint endx="2780" endy="530" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="199" widgetaid="200" xmi.id="605" >
+ <linepath>
+ <startpoint startx="4680" starty="1150" />
+ <endpoint endx="4680" endy="1220" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="6" indexb="4" widgetbid="195" widgetaid="225" xmi.id="615" >
+ <linepath>
+ <startpoint startx="4090" starty="1010" />
+ <endpoint endx="3250" endy="510" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="6" indexb="4" widgetbid="194" widgetaid="225" xmi.id="616" >
+ <linepath>
+ <startpoint startx="3870" starty="1010" />
+ <endpoint endx="2710" endy="530" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="6" indexb="1" widgetbid="194" widgetaid="220" xmi.id="625" >
+ <linepath>
+ <startpoint startx="1820" starty="1015" />
+ <endpoint endx="2500" endy="530" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="6" indexb="1" widgetbid="195" widgetaid="220" xmi.id="626" >
+ <linepath>
+ <startpoint startx="1680" starty="1015" />
+ <endpoint endx="3130" endy="510" />
+ <point x="1860" y="980" />
+ <point x="2660" y="690" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="6" indexb="3" widgetbid="194" widgetaid="233" xmi.id="645" >
+ <linepath>
+ <startpoint startx="3320" starty="1010" />
+ <endpoint endx="2640" endy="530" />
+ <point x="3060" y="840" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="6" indexb="3" widgetbid="195" widgetaid="233" xmi.id="646" >
+ <linepath>
+ <startpoint startx="3480" starty="1010" />
+ <endpoint endx="3210" endy="510" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="6" indexb="2" widgetbid="194" widgetaid="242" xmi.id="655" >
+ <linepath>
+ <startpoint startx="2380" starty="1015" />
+ <endpoint endx="2570" endy="530" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="6" indexb="2" widgetbid="195" widgetaid="242" xmi.id="656" >
+ <linepath>
+ <startpoint startx="2750" starty="1015" />
+ <endpoint endx="3170" endy="510" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="225" widgetaid="227" xmi.id="669" >
+ <linepath>
+ <startpoint startx="4620" starty="1530" />
+ <endpoint endx="4090" endy="1190" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="225" widgetaid="226" xmi.id="670" >
+ <linepath>
+ <startpoint startx="4160" starty="1770" />
+ <endpoint endx="3870" endy="1190" />
+ <point x="4120" y="1960" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="189" widgetaid="214" xmi.id="679" >
+ <linepath>
+ <startpoint startx="1250" starty="1010" />
+ <endpoint endx="2570" endy="210" />
+ <point x="1250" y="980" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="2" indexb="1" widgetbid="208" widgetaid="214" xmi.id="681" >
+ <linepath>
+ <startpoint startx="1320" starty="1590" />
+ <endpoint endx="1280" endy="1855" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="208" widgetaid="209" xmi.id="695" >
+ <linepath>
+ <startpoint startx="1560" starty="2230" />
+ <endpoint endx="1410" endy="2145" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="208" widgetaid="212" xmi.id="705" >
+ <linepath>
+ <startpoint startx="1340" starty="2515" />
+ <endpoint endx="1150" endy="2145" />
+ <point x="1150" y="2440" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="208" widgetaid="213" xmi.id="706" >
+ <linepath>
+ <startpoint startx="2285" starty="2090" />
+ <endpoint endx="1670" endy="1950" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" visibilityB="200" totalcountb="3" indexb="1" widgetbid="214" widgetaid="215" roleBdoc="" documentation="" roleAdoc="" type="503" changeabilityA="900" changeabilityB="900" visibilityA="200" >
+ <linepath>
+ <startpoint startx="1030" starty="1700" />
+ <endpoint endx="1180" endy="1590" />
+ <point x="1140" y="1640" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="214" widgetaid="226" xmi.id="708" >
+ <linepath>
+ <startpoint startx="3505" starty="2090" />
+ <endpoint endx="1465" endy="1200" />
+ <point x="1940" y="1870" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="5" linecolour="none" y="1965" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1367" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1465" linecolour="none" y="1205" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1368" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="211" widgetaid="208" xmi.id="715" >
+ <linepath>
+ <startpoint startx="1670" starty="2050" />
+ <endpoint endx="2530" endy="2535" />
+ <point x="1890" y="2080" />
+ <point x="2090" y="2370" />
+ <point x="2360" y="2460" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1675" linecolour="none" y="2045" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1369" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2495" linecolour="none" y="2495" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1370" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="217" widgetaid="211" xmi.id="716" >
+ <linepath>
+ <startpoint startx="2670" starty="2535" />
+ <endpoint endx="2720" endy="2400" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2665" linecolour="none" y="2495" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1371" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="2685" linecolour="none" y="2405" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1372" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" visibilityB="200" totalcountb="3" indexb="2" widgetbid="217" widgetaid="218" roleBdoc="" documentation="" roleAdoc="" type="503" changeabilityA="900" changeabilityB="900" visibilityA="200" >
+ <linepath>
+ <startpoint startx="2960" starty="2530" />
+ <endpoint endx="2840" endy="2400" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="233" widgetaid="242" xmi.id="721" >
+ <linepath>
+ <startpoint startx="3115" starty="1390" />
+ <endpoint endx="3160" endy="1270" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="5" linecolour="none" y="1335" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1373" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="5" linecolour="none" y="1265" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1374" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="220" widgetaid="242" xmi.id="722" >
+ <linepath>
+ <startpoint startx="2005" starty="1390" />
+ <endpoint endx="1750" endy="1285" />
+ <point x="1810" y="1370" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1965" linecolour="none" y="1355" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1375" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="1755" linecolour="none" y="1285" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1376" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="3" indexb="1" widgetbid="226" widgetaid="233" xmi.id="731" >
+ <linepath>
+ <startpoint startx="3480" starty="1530" />
+ <endpoint endx="3505" endy="1930" />
+ <point x="3810" y="1940" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="227" widgetaid="233" xmi.id="732" >
+ <linepath>
+ <startpoint startx="3640" starty="1270" />
+ <endpoint endx="4235" endy="1600" />
+ <point x="4200" y="1570" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="262" widgetaid="212" xmi.id="816" >
+ <linepath>
+ <startpoint startx="1890" starty="2680" />
+ <endpoint endx="1950" endy="2680" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="1" totalcountb="3" indexb="1" widgetbid="733" widgetaid="233" xmi.id="1058" >
+ <linepath>
+ <startpoint startx="3320" starty="1530" />
+ <endpoint endx="3330" endy="2485" />
+ </linepath>
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="5" linecolour="none" y="1505" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="709" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1377" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ <floatingtext usesdiagramfillcolour="1" width="30" usesdiagramusefillcolour="1" x="5" linecolour="none" y="2455" linewidth="none" usesdiagramlinewidth="1" posttext="" usesdiagramlinecolour="1" role="710" fillcolour="none" height="30" usefillcolor="1" pretext="+" isinstance="0" xmi.id="1378" text="" font="Bitstream Charter,12,-1,5,50,0,0,0,0,0" />
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="733" widgetaid="226" xmi.id="1059" >
+ <linepath>
+ <startpoint startx="4160" starty="2250" />
+ <endpoint endx="3530" endy="2485" />
+ </linepath>
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="2" indexb="1" widgetbid="217" widgetaid="214" xmi.id="1263" >
+ <linepath>
+ <startpoint startx="1465" starty="1400" />
+ <endpoint endx="2590" endy="2330" />
+ <point x="1920" y="1990" />
+ <point x="2150" y="2320" />
+ </linepath>
+ </assocwidget>
+ </associations>
+ </diagram>
+ </diagrams>
+ <listview>
+ <listitem open="1" type="800" id="-1" label="Ansichten" >
+ <listitem open="1" type="801" id="-1" label="Logische Ansicht" >
+ <listitem open="0" type="803" id="187" label="Lib Paket" />
+ <listitem open="1" type="803" id="192" label="Modul Paket" />
+ <listitem open="0" type="807" id="174" label="class diagram" />
+ <listitem open="0" type="818" id="188" >
+ <listitem open="1" type="813" id="189" />
+ </listitem>
+ <listitem open="1" type="818" id="186" >
+ <listitem open="1" type="813" id="194" >
+ <listitem open="0" type="815" id="889" />
+ <listitem open="0" type="815" id="892" />
+ <listitem open="0" type="815" id="891" />
+ <listitem open="0" type="815" id="890" />
+ </listitem>
+ <listitem open="1" type="813" id="195" >
+ <listitem open="0" type="815" id="921" />
+ <listitem open="0" type="815" id="920" />
+ <listitem open="0" type="815" id="919" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="280" >
+ <listitem open="1" type="813" id="281" />
+ <listitem open="1" type="813" id="282" />
+ <listitem open="1" type="813" id="283" />
+ <listitem open="1" type="813" id="284" />
+ </listitem>
+ <listitem open="1" type="818" id="207" >
+ <listitem open="1" type="813" id="208" >
+ <listitem open="0" type="815" id="1185" />
+ <listitem open="0" type="815" id="1186" />
+ <listitem open="0" type="815" id="1187" />
+ <listitem open="0" type="815" id="1189" />
+ <listitem open="0" type="815" id="1190" />
+ <listitem open="0" type="815" id="1193" />
+ <listitem open="0" type="815" id="1194" />
+ <listitem open="0" type="815" id="1195" />
+ <listitem open="0" type="815" id="1184" />
+ <listitem open="0" type="815" id="1188" />
+ <listitem open="0" type="815" id="1191" />
+ <listitem open="0" type="815" id="1192" />
+ </listitem>
+ <listitem open="1" type="813" id="209" >
+ <listitem open="0" type="815" id="1199" />
+ <listitem open="0" type="815" id="1201" />
+ <listitem open="0" type="815" id="1196" />
+ <listitem open="0" type="815" id="1197" />
+ <listitem open="0" type="815" id="1198" />
+ <listitem open="0" type="815" id="1200" />
+ <listitem open="0" type="815" id="1202" />
+ </listitem>
+ <listitem open="1" type="813" id="210" />
+ <listitem open="1" type="813" id="211" >
+ <listitem open="0" type="815" id="1244" />
+ <listitem open="0" type="815" id="1245" />
+ <listitem open="0" type="815" id="1246" />
+ <listitem open="0" type="815" id="1250" />
+ <listitem open="0" type="815" id="1251" />
+ <listitem open="0" type="815" id="1252" />
+ <listitem open="0" type="815" id="1253" />
+ <listitem open="0" type="815" id="1241" />
+ <listitem open="0" type="815" id="1242" />
+ <listitem open="0" type="815" id="1243" />
+ <listitem open="0" type="815" id="1247" />
+ <listitem open="0" type="815" id="1248" />
+ <listitem open="0" type="815" id="1249" />
+ </listitem>
+ <listitem open="1" type="813" id="212" >
+ <listitem open="0" type="815" id="1212" />
+ <listitem open="0" type="815" id="1213" />
+ <listitem open="0" type="815" id="1214" />
+ <listitem open="0" type="815" id="1215" />
+ <listitem open="0" type="815" id="1216" />
+ <listitem open="0" type="815" id="1218" />
+ <listitem open="0" type="815" id="1220" />
+ <listitem open="0" type="815" id="1221" />
+ <listitem open="0" type="815" id="1222" />
+ <listitem open="0" type="815" id="1209" />
+ <listitem open="0" type="815" id="1210" />
+ <listitem open="0" type="815" id="1211" />
+ <listitem open="0" type="815" id="1217" />
+ <listitem open="0" type="815" id="1219" />
+ </listitem>
+ <listitem open="1" type="813" id="213" >
+ <listitem open="0" type="815" id="1235" />
+ <listitem open="0" type="815" id="1236" />
+ <listitem open="0" type="815" id="1238" />
+ <listitem open="0" type="815" id="1240" />
+ <listitem open="0" type="815" id="1232" />
+ <listitem open="0" type="815" id="1233" />
+ <listitem open="0" type="815" id="1234" />
+ <listitem open="0" type="815" id="1237" />
+ <listitem open="0" type="815" id="1239" />
+ </listitem>
+ <listitem open="1" type="813" id="215" >
+ <listitem open="0" type="815" id="1181" />
+ <listitem open="0" type="815" id="1182" />
+ <listitem open="0" type="815" id="1183" />
+ </listitem>
+ <listitem open="1" type="813" id="214" >
+ <listitem open="0" type="815" id="1154" />
+ <listitem open="0" type="815" id="1160" />
+ <listitem open="0" type="815" id="1162" />
+ <listitem open="0" type="815" id="1163" />
+ <listitem open="0" type="815" id="1164" />
+ <listitem open="0" type="815" id="1165" />
+ <listitem open="0" type="815" id="1166" />
+ <listitem open="0" type="815" id="1167" />
+ <listitem open="0" type="815" id="1168" />
+ <listitem open="0" type="815" id="1170" />
+ <listitem open="0" type="815" id="1172" />
+ <listitem open="0" type="815" id="1173" />
+ <listitem open="0" type="815" id="1175" />
+ <listitem open="0" type="815" id="1177" />
+ <listitem open="0" type="815" id="1178" />
+ <listitem open="0" type="815" id="1179" />
+ <listitem open="0" type="815" id="1180" />
+ <listitem open="0" type="815" id="1174" />
+ <listitem open="0" type="815" id="1159" />
+ <listitem open="0" type="815" id="1161" />
+ <listitem open="0" type="815" id="1169" />
+ <listitem open="0" type="815" id="1171" />
+ <listitem open="0" type="815" id="1157" />
+ <listitem open="0" type="815" id="1158" />
+ <listitem open="0" type="815" id="1155" />
+ <listitem open="0" type="815" id="1156" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="216" >
+ <listitem open="1" type="813" id="217" >
+ <listitem open="0" type="815" id="1258" />
+ <listitem open="0" type="815" id="1260" />
+ <listitem open="0" type="815" id="1261" />
+ <listitem open="0" type="815" id="1262" />
+ <listitem open="0" type="815" id="1259" />
+ </listitem>
+ <listitem open="1" type="813" id="218" >
+ <listitem open="0" type="815" id="1254" />
+ <listitem open="0" type="815" id="1256" />
+ <listitem open="0" type="815" id="1257" />
+ <listitem open="0" type="815" id="1255" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="264" >
+ <listitem open="1" type="813" id="265" />
+ <listitem open="1" type="813" id="268" />
+ <listitem open="1" type="813" id="266" />
+ <listitem open="1" type="813" id="267" />
+ </listitem>
+ <listitem open="1" type="818" id="219" >
+ <listitem open="1" type="813" id="220" >
+ <listitem open="0" type="815" id="1143" />
+ <listitem open="0" type="815" id="1144" />
+ <listitem open="0" type="815" id="1145" />
+ <listitem open="0" type="815" id="1147" />
+ <listitem open="0" type="815" id="1149" />
+ <listitem open="0" type="815" id="1150" />
+ <listitem open="0" type="815" id="1151" />
+ <listitem open="0" type="815" id="1152" />
+ <listitem open="0" type="815" id="1153" />
+ <listitem open="0" type="815" id="1148" />
+ <listitem open="0" type="815" id="1146" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="198" >
+ <listitem open="1" type="813" id="199" >
+ <listitem open="0" type="815" id="928" />
+ </listitem>
+ <listitem open="1" type="813" id="200" >
+ <listitem open="0" type="815" id="923" />
+ <listitem open="0" type="815" id="924" />
+ <listitem open="0" type="815" id="926" />
+ <listitem open="0" type="815" id="927" />
+ <listitem open="0" type="815" id="925" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="224" >
+ <listitem open="1" type="813" id="225" >
+ <listitem open="0" type="815" id="931" />
+ <listitem open="0" type="815" id="932" />
+ <listitem open="0" type="815" id="933" />
+ <listitem open="0" type="815" id="935" />
+ <listitem open="0" type="815" id="936" />
+ <listitem open="0" type="815" id="937" />
+ <listitem open="0" type="815" id="934" />
+ </listitem>
+ <listitem open="1" type="813" id="226" >
+ <listitem open="0" type="815" id="943" />
+ <listitem open="0" type="815" id="945" />
+ <listitem open="0" type="815" id="946" />
+ <listitem open="0" type="815" id="948" />
+ <listitem open="0" type="815" id="947" />
+ <listitem open="0" type="815" id="949" />
+ <listitem open="0" type="815" id="950" />
+ <listitem open="0" type="815" id="951" />
+ <listitem open="0" type="815" id="953" />
+ <listitem open="0" type="815" id="954" />
+ <listitem open="0" type="815" id="956" />
+ <listitem open="0" type="815" id="955" />
+ <listitem open="0" type="815" id="957" />
+ <listitem open="0" type="815" id="962" />
+ <listitem open="0" type="815" id="963" />
+ <listitem open="0" type="815" id="959" />
+ <listitem open="0" type="815" id="958" />
+ <listitem open="0" type="815" id="960" />
+ <listitem open="0" type="815" id="964" />
+ <listitem open="0" type="815" id="952" />
+ <listitem open="0" type="815" id="944" />
+ </listitem>
+ <listitem open="1" type="813" id="227" >
+ <listitem open="0" type="815" id="938" />
+ <listitem open="0" type="815" id="939" />
+ <listitem open="0" type="815" id="941" />
+ <listitem open="0" type="815" id="942" />
+ <listitem open="0" type="815" id="940" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="269" >
+ <listitem open="1" type="813" id="270" />
+ <listitem open="1" type="813" id="271" />
+ <listitem open="1" type="813" id="272" />
+ <listitem open="1" type="813" id="273" />
+ </listitem>
+ <listitem open="1" type="818" id="232" >
+ <listitem open="1" type="813" id="233" >
+ <listitem open="0" type="815" id="1060" />
+ <listitem open="0" type="815" id="1061" />
+ <listitem open="0" type="815" id="1062" />
+ <listitem open="0" type="815" id="1063" />
+ <listitem open="0" type="815" id="1064" />
+ <listitem open="0" type="815" id="1066" />
+ <listitem open="0" type="815" id="1067" />
+ <listitem open="0" type="815" id="1069" />
+ <listitem open="0" type="815" id="1070" />
+ <listitem open="0" type="815" id="1071" />
+ <listitem open="0" type="815" id="1072" />
+ <listitem open="0" type="815" id="1073" />
+ <listitem open="0" type="815" id="1074" />
+ <listitem open="0" type="815" id="1075" />
+ <listitem open="0" type="815" id="1076" />
+ <listitem open="0" type="815" id="1077" />
+ <listitem open="0" type="815" id="1079" />
+ <listitem open="0" type="815" id="1080" />
+ <listitem open="0" type="815" id="1082" />
+ <listitem open="0" type="815" id="1068" />
+ <listitem open="0" type="815" id="1065" />
+ <listitem open="0" type="815" id="1078" />
+ <listitem open="0" type="815" id="1081" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="196" />
+ <listitem open="0" type="818" id="285" >
+ <listitem open="1" type="813" id="286" />
+ <listitem open="1" type="813" id="287" />
+ <listitem open="1" type="813" id="288" />
+ <listitem open="1" type="813" id="289" />
+ <listitem open="1" type="813" id="825" />
+ <listitem open="1" type="813" id="291" />
+ </listitem>
+ <listitem open="1" type="818" id="236" >
+ <listitem open="1" type="813" id="237" />
+ <listitem open="1" type="813" id="238" />
+ <listitem open="1" type="813" id="733" >
+ <listitem open="0" type="815" id="991" />
+ <listitem open="0" type="815" id="992" />
+ <listitem open="0" type="815" id="993" />
+ <listitem open="0" type="815" id="994" />
+ <listitem open="0" type="815" id="995" />
+ <listitem open="0" type="815" id="996" />
+ <listitem open="0" type="815" id="998" />
+ <listitem open="0" type="815" id="999" />
+ <listitem open="0" type="815" id="997" />
+ <listitem open="0" type="815" id="1000" />
+ <listitem open="0" type="815" id="1001" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="818" id="261" >
+ <listitem open="1" type="813" id="262" >
+ <listitem open="0" type="815" id="1226" />
+ <listitem open="0" type="815" id="1229" />
+ <listitem open="0" type="815" id="1223" />
+ <listitem open="0" type="815" id="1224" />
+ <listitem open="0" type="815" id="1227" />
+ <listitem open="0" type="815" id="1228" />
+ <listitem open="0" type="815" id="1231" />
+ <listitem open="0" type="815" id="1225" />
+ <listitem open="0" type="815" id="1230" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="292" >
+ <listitem open="1" type="813" id="293" />
+ <listitem open="1" type="813" id="294" />
+ </listitem>
+ <listitem open="0" type="818" id="295" >
+ <listitem open="1" type="813" id="296" />
+ </listitem>
+ <listitem open="1" type="818" id="297" />
+ <listitem open="1" type="818" id="239" >
+ <listitem open="1" type="813" id="240" />
+ <listitem open="1" type="813" id="241" />
+ <listitem open="1" type="813" id="242" >
+ <listitem open="0" type="815" id="1083" />
+ <listitem open="0" type="815" id="1084" />
+ <listitem open="0" type="815" id="1085" />
+ <listitem open="0" type="815" id="1086" />
+ <listitem open="0" type="815" id="1088" />
+ <listitem open="0" type="815" id="1089" />
+ <listitem open="0" type="815" id="1093" />
+ <listitem open="0" type="815" id="1092" />
+ <listitem open="0" type="815" id="1094" />
+ <listitem open="0" type="815" id="1095" />
+ <listitem open="0" type="815" id="1097" />
+ <listitem open="0" type="815" id="1098" />
+ <listitem open="0" type="815" id="1099" />
+ <listitem open="0" type="815" id="1101" />
+ <listitem open="0" type="815" id="1102" />
+ <listitem open="0" type="815" id="1103" />
+ <listitem open="0" type="815" id="1104" />
+ <listitem open="0" type="815" id="1105" />
+ <listitem open="0" type="815" id="1106" />
+ <listitem open="0" type="815" id="1107" />
+ <listitem open="0" type="815" id="1108" />
+ <listitem open="0" type="815" id="1109" />
+ <listitem open="0" type="815" id="1110" />
+ <listitem open="0" type="815" id="1112" />
+ <listitem open="0" type="815" id="1113" />
+ <listitem open="0" type="815" id="1114" />
+ <listitem open="0" type="815" id="1115" />
+ <listitem open="0" type="815" id="1116" />
+ <listitem open="0" type="815" id="1100" />
+ <listitem open="0" type="815" id="1087" />
+ <listitem open="0" type="815" id="1091" />
+ <listitem open="0" type="815" id="1090" />
+ <listitem open="0" type="815" id="1096" />
+ <listitem open="0" type="815" id="1111" />
+ </listitem>
+ </listitem>
+ <listitem open="0" type="818" id="298" >
+ <listitem open="1" type="813" id="299" />
+ <listitem open="1" type="813" id="300" />
+ <listitem open="1" type="813" id="301" />
+ <listitem open="1" type="813" id="302" />
+ </listitem>
+ <listitem open="0" type="818" id="303" >
+ <listitem open="1" type="813" id="304" />
+ <listitem open="1" type="813" id="305" />
+ <listitem open="1" type="813" id="306" />
+ <listitem open="1" type="813" id="307" />
+ <listitem open="1" type="813" id="309" />
+ <listitem open="1" type="813" id="308" />
+ </listitem>
+ <listitem open="1" type="818" id="310" />
+ <listitem open="0" type="818" id="311" >
+ <listitem open="1" type="813" id="313" />
+ </listitem>
+ <listitem open="0" type="818" id="312" >
+ <listitem open="1" type="813" id="314" />
+ </listitem>
+ <listitem open="0" type="830" id="-1" label="Datentypen" >
+ <listitem open="1" type="829" id="177" />
+ <listitem open="1" type="829" id="176" />
+ <listitem open="1" type="829" id="179" />
+ <listitem open="1" type="829" id="178" />
+ <listitem open="1" type="829" id="175" />
+ <listitem open="1" type="829" id="180" />
+ <listitem open="1" type="829" id="181" />
+ </listitem>
+ </listitem>
+ <listitem open="1" type="802" id="-1" label="Anwendungsfallansicht" />
+ <listitem open="1" type="821" id="-1" label="Komponentenansicht" />
+ <listitem open="1" type="827" id="-1" label="Verteilungsansicht" />
+ </listitem>
+ </listview>
+ <codegeneration/>
+ </XMI.extensions>
+</XMI>
Added: packages/thuban/branches/upstream/current/Doc/manual/Makefile
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/Makefile 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/Makefile 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,41 @@
+SRC_MAN=thuban-manual.xml
+SRC_MAN_DE=thuban-manual-de.xml
+SRC_IMAGES=$(wildcard images/*.png)
+EPS_IMAGES=$(patsubst %.png,%.eps,$(SRC_IMAGES))
+
+all: images man-all
+
+man-all: man-all-en man-all-de
+
+man-all-en: man-html man-dvi man-ps man-pdf man-rtf
+man-all-de: man-html-de man-dvi-de man-ps-de man-pdf-de man-rtf-de
+
+man-html:
+ db2html $(SRC_MAN)
+man-dvi: images
+ db2dvi $(SRC_MAN)
+man-ps: images
+ db2ps $(SRC_MAN)
+man-pdf: images
+ db2pdf $(SRC_MAN)
+man-rtf:
+ db2rtf $(SRC_MAN)
+
+man-html-de:
+ db2html $(SRC_MAN_DE)
+man-dvi-de: images
+ db2dvi $(SRC_MAN_DE)
+man-ps-de: images
+ db2ps $(SRC_MAN_DE)
+man-pdf-de: images
+ db2pdf $(SRC_MAN_DE)
+man-rtf-de:
+ db2rtf $(SRC_MAN_DE)
+
+images: $(EPS_IMAGES)
+
+%.eps: %.png
+ convert $< $@
+
+.PHONY: images
+
Added: packages/thuban/branches/upstream/current/Doc/manual/README
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,17 @@
+
+README for the Thuban Manual Sources
+====================================
+$Revision: 1367 $
+
+
+The manual is written using DocBook XML. To convert to other formats use
+the docbook tools. Examples:
+
+Convert to PostScript (the output will be manual.ps)
+
+ $ db2ps manual.xml
+
+to HTML (the output will be in a subdirectory manual/)
+
+ $ db2html manual.xml
+
Added: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_close.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_close.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_dock.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_legend_dock.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.ps
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.ps 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.ps 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,12899 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%For: Jonathan Coles,,,
+%%CreationDate: Fri 18 Jul 2003 02:24:54 PM CEST
+%%Title: 1_2_mainwindow.ps
+%%Creator: Sketch 0.6.14
+%%Pages: 1
+%%BoundingBox: 16 31 519 370
+%%Extensions: CMYK
+%%DocumentSuppliedResources: (atend)
+%%DocumentNeededResources: font Helvetica-Bold
+%%EndComments
+
+%%BeginProlog
+%%BeginResource: procset Linux-Sketch-Procset 1.0 2
+/SketchDict 100 dict def
+SketchDict begin
+/bd { bind def } bind def
+/x { exch } bd
+/xd { exch def } bd
+/PI 3.14159265358979323846264338327 def
+/radgrad { 180 mul PI div } bd
+/skstartmatrix matrix currentmatrix def
+/tmpmat matrix def
+/ISOLatin1Encoding dup where
+{ pop pop }
+{ [/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand
+/quoteright /parenleft /parenright /asterisk /plus /comma /minus /period
+/slash /zero /one /two /three /four /five /six /seven /eight /nine /colon
+/semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J
+/K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash
+/bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i
+/j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright
+/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /dotlessi /grave /acute /circumflex /tilde /macron /breve
+/dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek
+/caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen
+/registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu
+/paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright
+/onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex
+/Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex
+/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve
+/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute
+/Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute
+/acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute
+/ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde
+/ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave
+/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def
+}
+ifelse
+/arct dup where
+{pop pop}
+{
+/arct {arcto pop pop pop pop} bd
+}
+ifelse
+/size 0 def
+/fontname 0 def
+/newfont 0 def
+/sf {
+/size xd
+/fontname xd
+fontname findfont
+dup /Encoding get StandardEncoding eq
+{
+dup
+length dict /newfont xd
+{
+1 index
+/FID ne
+{ newfont 3 1 roll put }
+{ pop pop }
+ifelse
+} forall
+newfont /Encoding ISOLatin1Encoding put
+fontname newfont definefont
+}
+if
+size scalefont setfont
+} bd
+/pusht {matrix currentmatrix} bd
+/popt {setmatrix} bd
+/pushc {gsave} bd
+/popc {grestore} bd
+/rgb {setrgbcolor} bd
+/w { setlinewidth } bd
+/j { setlinejoin } bd
+/J { setlinecap } bd
+/d { setdash } bd
+/F { eofill } bd
+/f { closepath F } bd
+/S {
+pusht
+skstartmatrix setmatrix stroke
+popt
+} bd
+/s { closepath S } bd
+/m { moveto } bd
+/l { lineto } bd
+/c { curveto } bd
+/txt {
+/tmpmat tmpmat currentmatrix def
+dup type /arraytype eq {concat} {translate} ifelse
+0 0 m
+tmpmat
+} bd
+/T {txt x show popt} bd
+/P {txt x true charpath popt} bd
+/TP {txt x dup show 0 0 m true charpath popt} bd
+/C {newpath 0 360 arc} bd
+/R {
+2 copy m
+x 2 index l
+x 2 index x l
+l
+closepath
+} bd
+/ellipse {
+dup type /arraytype eq
+{
+pusht x concat
+0 0 1.0 C
+popt
+}
+{
+pusht 5 1 roll
+4 -1 roll concat
+newpath
+dup 2 eq {
+0 0 m
+} if
+3 1 roll
+radgrad x
+radgrad x
+0 0 1 5 -2 roll
+arc
+0 ne { closepath } if
+popt
+}
+ifelse
+} bd
+/radius1 0 def
+/radius2 0 def
+/factor 0 def
+/rect {
+dup type /arraytype eq
+{
+pusht x concat
+0 0 m 1 0 l 1 1 l 0 1 l closepath
+popt
+}
+{
+/radius2 xd
+/radius1 xd
+pusht x concat
+radius1 radius2 div 1 scale
+0 radius2 m
+0 1 radius2 1 radius2 arct
+radius2 radius1 div
+dup 1 1 index 0 radius2 arct
+0 0 0 radius2 arct
+0 0 0 1 radius2 arct
+closepath
+popt
+}
+ifelse
+} bd
+/buf 0 def
+/width 0 def
+/height 0 def
+/skcimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width 3 mul string def
+width height scale
+width height 8
+[width 0 0 height neg 0 height]
+{ currentfile buf readhexstring pop } bind
+false 3 colorimage
+tmpmat setmatrix
+} bd
+/skgimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width string def
+width height scale
+width height 8
+[width 0 0 height neg 0 height]
+{ currentfile buf readhexstring pop } bind
+image
+tmpmat setmatrix
+} bd
+/rclip {
+4 2 roll m
+dup 0 x rlineto
+x 0 rlineto
+neg 0 x rlineto
+closepath
+clip
+} bd
+/skeps {
+10 dict begin
+/sk_state save def
+concat
+3 index neg 3 index neg translate
+rclip
+0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+10 setmiterlimit [ ] 0 setdash
+newpath
+/sk_dict_count countdictstack def
+/sk_count count 1 sub def
+userdict begin
+/showpage { } def
+/languagelevel where
+{
+pop
+languagelevel 1 ne
+{
+false setstrokeadjust
+false setoverprint
+} if
+} if
+} bd
+/skepsend {
+count sk_count sub { pop } repeat
+countdictstack sk_dict_count sub { end } repeat
+sk_state restore
+end
+} bd
+/gradidx 0 def
+/gradient {
+3 mul array
+/gradidx 0 def
+} bd
+/$ {
+3 index gradidx 5 -1 roll put
+2 index gradidx 1 add 4 -1 roll put
+1 index gradidx 2 add 3 -1 roll put
+/gradidx gradidx 3 add def
+} bd
+/! {
+3
+{
+dup dup gradidx dup 3 1 roll 3 sub get put
+/gradidx gradidx 1 add def
+}
+repeat
+} bd
+/gradcolor {
+3 mul dup 2 add 1 exch % idx 1 idx+2
+{
+1 index exch % array array i
+get % array component
+exch % component array
+}
+for
+4 1 roll
+} bd
+/x0 0 def /y0 0 def /x1 0 def /y1 0 def
+/left 0 def /right 0 def /top 0 def /bottom 0 def
+/numcolors 0 def
+/axial {
+/y1 xd /x1 xd /y0 xd /x0 xd
+dup length 3 idiv /numcolors xd
+pusht exch % ctm array
+x0 x1 ne y0 y1 ne or
+{
+x0 y0 translate
+[x1 x0 sub y1 y0 sub dup neg 2 index 0 0] concat
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+0 gradcolor rgb clippath f
+0 1 numcolors 1 sub
+{
+dup numcolors div
+3 1 roll
+gradcolor rgb
+exch
+bottom right top R f
+}
+for
+}
+if
+pop
+popt
+} bd
+/r0 0 def /r1 0 def /dr 0 def
+/radial {
+/r1 xd /r0 xd /y0 xd /x0 xd
+/dr r1 r0 sub def
+dup length 3 idiv /numcolors xd
+pusht exch % ctm array
+r0 r1 ne
+{
+x0 y0 translate
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+dr 0 gt {numcolors 1 sub}{0} ifelse gradcolor rgb
+clippath f
+dr 0 gt {numcolors 1 sub -1 0} { 0 1 numcolors 1 sub} ifelse
+{
+dup numcolors div dr mul r0 add
+3 1 roll
+gradcolor rgb
+exch
+0 0 3 -1 roll C f
+}
+for
+}
+if
+pop
+popt
+} bd
+/max {
+2 copy lt {exch} if pop
+} bd
+/conical {
+pusht 5 1 roll
+3 1 roll /y0 xd /x0 xd
+x0 y0 translate
+radgrad rotate
+dup length 3 idiv /numcolors xd
+clippath flattenpath pathbbox newpath
+4 { abs 4 1 roll} repeat
+3 { max } repeat
+2 mul
+dup scale
+0 gradcolor rgb
+0 0 1 0 360 arc f
+1 1 numcolors 1 sub
+{
+dup numcolors div 180 mul
+3 1 roll
+gradcolor rgb
+exch
+0 0 moveto
+0 0 1 4 -1 roll dup neg arc
+closepath f
+}
+for
+pop
+popt
+} bd
+/XStep 0 def /YStep 0 def /imagedata 0 def /components 0 def
+/tileimage2 {
+exch 4 2 roll
+/height xd
+/width xd
+mark
+/components 2 index
+/PatternType 1
+/PaintType 1
+/TilingType 1
+/BBox [0 0 width height]
+/XStep width
+/YStep height
+/PaintProc {
+begin
+XStep YStep 8
+matrix
+imagedata
+false
+components
+colorimage
+end
+}
+counttomark 2 div cvi dup dict begin
+{ def } repeat
+pop currentdict end
+dup
+/imagedata
+4 -1 roll
+width height mul mul string
+currentfile exch readhexstring pop
+put
+exch
+makepattern
+setpattern
+clippath
+eofill
+} bd
+/tileimage1 {
+concat
+/components xd
+/height xd
+/width xd
+/imagedata
+currentfile
+width height mul components mul string
+readhexstring pop
+def
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+left width div floor width mul
+bottom height div floor height mul
+translate
+top bottom sub height div ceiling cvi
+{
+gsave
+right left sub width div ceiling cvi
+{
+width height 8 matrix
+components 1 eq
+{
+{ imagedata }
+image
+}
+{
+imagedata
+false components
+colorimage
+}
+ifelse
+width 0 translate
+}
+repeat
+grestore
+0 height translate
+}
+repeat
+} bd
+/makepattern where
+{
+pop
+/tileimage /tileimage2 load def
+}
+{
+/tileimage /tileimage1 load def
+}
+ifelse
+end
+%%EndResource
+%%EndProlog
+
+%%BeginSetup
+%%IncludeResource: font Helvetica-Bold
+
+10.433 setmiterlimit
+%%EndSetup
+
+%%Page: 1 1
+SketchDict begin
+497 332 [1 0 0 1 19.6378 35.9449] true
+%%BeginData: 12377 Hex Lines
+skcimg
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CE848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848486848482848486848482
+848486848482848486848482848C868C8482848486848486848C868C8482848C868C8486848C868C
+8486848C868C8486848C868C8486848C868C8486848C8A8C8486848C868C8486848C8A8C8486848C
+8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C
+8C8A8C8C8E8C8C8A8C948E948C8A8C8C8E8C8C8E8C948E948C8A8C948E948C8E8C948E948C8E8C94
+8E948C8E8C948E948C8E8C948E948C8E8C9492948C8E8C948E948C8E8C9492948C8E8C9492948C8E
+8C9492948C8E8C949294948E949492948C8E8C949294949294949294949294949294949294949294
+94929494929494929494929494929494929494929494969494929494969494929494969494929494
+96949492949C969C9492949496949496949C969C9492949C969C9496949C969C9496949C969C9496
+949C969C9496949C969C9496949C9A9C9496949C969C9496949C9A9C9496949C9A9C9496949C9A9C
+9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A
+9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA5
+9C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5
+A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6AD
+A5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6
+ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEADADAAADADAEADADAAADB5AEB5ADAAADAD
+AEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAE
+ADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5
+ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6
+B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABD
+B5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDC5BEC5BDBABDBDBEBDBDBEBDC5BEC5
+BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5
+BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE84828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+848482848482848482848482848486848482848482848482848C868C8482848486848482848C868C
+8482848C868C8482848C868C8486848C868C8482848C868C8486848C868C8486848C868C8486848C
+868C8486848C868C8486848C868C8486848C8A8C8C868C8C8A8C8486848C8A8C8C868C8C8A8C8486
+848C8A8C8C868C8C8A8C8C868C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C
+8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8A8C8C8A8C948E948C8A8C8C8E8C8C8A8C948E948C8A8C94
+8E948C8A8C948E948C8E8C948E948C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E
+8C948E948C8E8C948E948C8E8C949294948E949492948C8E8C949294948E949492948C8E8C949294
+948E94949294948E9494929494929494929494929494929494929494929494929494929494929494
+92949492949496949492949492949492949C969C9492949496949492949C969C9492949C969C9492
+949C969C9496949C969C9492949C969C9496949C969C9496949C969C9496949C969C9496949C969C
+9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C969C9C
+9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A
+9C9C9E9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A9CA59EA59C9A9CA59EA59C9A9CA59EA5
+9C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5
+9EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5A2A5A59E
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5
+A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A6A5AD
+A6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6
+A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADA6ADADAAADADA6ADADAAAD
+ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADAD
+AAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAA
+ADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5
+ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2
+B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BD
+BABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6BDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDC5BEC5
+BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5
+BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBE
+BDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE8482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848486848482848486848482848486848482848486848482848C868C8482848486848486
+848C868C8482848C868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C
+8486848C868C8486848C8A8C8486848C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C
+8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C948E948C8A8C8C8E8C8C8E8C948E94
+8C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C9492948C8E8C94
+8E948C8E8C9492948C8E8C9492948C8E8C9492948C8E8C949294948E949492948C8E8C9492949492
+94949294949294949294949294949294949294949294949294949294949294949294949294949694
+9492949496949492949496949492949496949492949C969C9492949496949496949C969C9492949C
+969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9496949C969C9496
+949C9A9C9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C
+9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C
+9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E
+9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A5
+9C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5
+A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2
+A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6AD
+A5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5AD
+AAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAA
+ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEAD
+ADAAADADAEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5
+AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAE
+ADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5
+B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6
+B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABD
+B5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBA
+BDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5
+BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5
+C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF424142C5C2C5C5C2C5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CE84828484828484828484828484828484828484828484828484828484828484
+82840000000000000000000000008482848482848482848482848482848486848482848482848482
+848C868C8482848486848482848C868C8482848C868C8482848C868C8486848C868C8482848C868C
+8486848C868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C8C868C8C
+8A8C8486848C8A8C8C868C8C8A8C8C868C8C8A8C8C868C8C8A8C8C868C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8A8C8C8A8C948E94
+8C8A8C8C8E8C8C8A8C948E948C8A8C948E948C8A8C948E948C8E8C948E948C8A8C948E948C8E8C94
+8E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C949294948E949492948C8E
+8C949294948E94949294948E94949294948E94949294948E94949294949294949294949294949294
+9492949492949492949492949492949492949492949496949492949492949492949C969C94929494
+96949492949C969C9492949C969C9492949C969C9496949C969C9492949C969C9496949C969C9496
+949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C
+9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A
+9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA5
+9C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5
+A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6AD
+A5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADA6ADADAAADADA6
+ADADAAADADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAAADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5
+AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAE
+ADB5AEB5ADAEADB5AEB5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5B2B5B5AEB5B5B2B5
+B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2
+B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6BDBDBABDBDB6BDBD
+BABDBDB6BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5
+BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5
+BEC5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5BE
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE8482848482840000008482848482848482848482
+84848284848284848284000000000000000000000000000000000000000000848284848284848284
+848284848284848284848284848284848284848284D6D2CED6D2CE84828484828484868484828484
+86848482848486848482848486848482848C868C848284D6D2CED6D2CE8C868C8482848C868C8486
+848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C8486848C868C8486848C8A8C
+8486848C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C8A8C8C8A8C8C8A8C8C8A8C8C
+8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A
+8C8C8E8C8C8A8C8C8E8C8C8A8CD6D2CED6D2CE8C8E8C8C8E8C948E948C8A8C948E948C8E8C948E94
+8C8E8C948E948C8E8C948E948C8E8C948E948C8E8C9492948C8E8C948E948C8E8C949294D6D2CED6
+D2CE8C8E8C9492948C8E8C949294948E949492948C8E8C9492949492949492949492949492949492
+94949294949294949294949294949294949294949294949294949694949294949694949294949694
+9492949496949492949C969C9492949496949496949C969C9492949C969C9496949C969C9496949C
+969C9496949C969C9496949C969C9496949C9A9C9496949C969C9496949C9A9C9496949C9A9C9496
+949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C
+9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C
+9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E
+9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5
+9C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5
+A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2
+A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6AD
+A5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADA5A6A5AD
+AAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAA
+ADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEADADAAADADAEADADAAADB5AEB5
+ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5
+AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AE
+B5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5BDB6BDB5B2B5B5
+B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6
+B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABD
+B5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDC5BEC5BDBABDBDBEBDBDBE
+BDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5
+BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5
+C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE000000000000000000000000
+000000000000000000000000000000D6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284848284848284
+000000848284000000000000848284000000848284000000FF0000FF000000000000FF0000FF0000
+0000848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8C868CD6D2CED6D2CE8482
+848C868C8482848C868C8482848C868C8486848C868C8482848C868C8486848C868CD6D2CED6D2CE
+8486848C868C8486848C868C8486848C868C8486848C8A8C8C868C8C8A8C8486848C8A8C8C868C8C
+8A8C8486848C8A8C8C868C8C8A8C8C868C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8A8C8C8A8C8C8A8CD6D2CED6D2CED6D2CED6D2CE8C8A8C948E948C8A8C8C8E8C8C8A8C948E94
+8C8A8C948E948C8A8C948E948C8E8C948E948C8A8C948E94D6D2CED6D2CE8C8E8C948E948C8E8C94
+8E948C8E8C948E948C8E8C948E948C8E8C949294948E949492948C8E8C949294948E949492948C8E
+8C949294948E94D6D2CED6D2CE949294949294949294949294949294949294949294949294949294
+9492949492949492949496949492949492949492949C969C9492949496949492949C969C9492949C
+969C9492949C969C9496949C969C9492949C969C9496949C969C9496949C969C9496949C969C9496
+949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C
+9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9E9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A9CA59EA59C9A9CA59EA59C9A
+9CA59EA59C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA5
+9C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5
+A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A6A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6AD
+A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADA6ADADAAADADA6
+ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEAD
+ADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5
+AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAE
+ADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5B2B5B5AEB5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2
+B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABD
+B5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6BDBDBABDBDBABDBD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5
+BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5
+C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE00
+0000000000000000000000000000000000000000000000000000D6D2CED6D2CE848284424142C5C2
+C5C5C2C5FFFFFFD6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CE000000000000
+D6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CE848284848284FF0000848284848284848284000000848284848284848284000000FF0000FF00
+0000000000FF0000FF00000000848284848284848284848284848284D6D2CED6D2CE848284848284
+848284D6D2CED6D2CE8486848482848486848482848486848482848486848482848C868C84828484
+8684848684D6D2CED6D2CE8C868C8486848C868C8486848C868C8486848C868C8486848C868C8486
+848C8A8C8486848C868C8486848C8A8C8486848C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C
+8486848C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8CD6D2CED6D2CE8C8A8C8C8A8C8C8A8C8C
+8A8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C948E948C8A8CD6D2CED6D2
+CE948E948C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C949294
+8C8E8C948E948C8E8C9492948C8E8C949294D6D2CED6D2CE8C8E8C949294948E949492948C8E8C94
+92949492949492949492949492949492949492949492949492949492949492949492949492949492
+949496949492949496949492949496949492949496949492949C969C9492949496949496949C969C
+9492949C969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9496949C
+969C9496949C9A9C9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A
+9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C
+9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA5
+9EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E
+9CA5A2A59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5
+A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5
+A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6
+A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAAD
+A5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADAD
+AAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAA
+ADADAEADADAAADADAEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5
+ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5
+B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2
+B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5
+B5B2B5B5B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BD
+B6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6
+B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABD
+BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBD
+BEBDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBE
+BDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5
+BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6
+D2CE000000000000D6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CE848284848284848284FF0000848284FF0000FF0000848284FF0000
+84828400000084000000000000000000000000FF00000000848284848284848284848684848284D6
+D2CED6D2CE8C868C848284848684D6D2CED6D2CED6D2CED6D2CED6D2CE8C868C848684D6D2CED6D2
+CE8C868C848684D6D2CED6D2CE8C868CD6D2CED6D2CED6D2CED6D2CED6D2CE8C868C8486848C8A8C
+D6D2CED6D2CED6D2CED6D2CE8C868C8C8A8CD6D2CED6D2CED6D2CED6D2CED6D2CE8C8A8C8C8A8C8C
+8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8CD6D2CED6D2
+CE948E948C8A8C8C8E8CD6D2CED6D2CED6D2CED6D2CE8C8A8C948E94D6D2CED6D2CED6D2CED6D2CE
+8C8E8C948E94D6D2CED6D2CE8C8E8C948E94D6D2CED6D2CED6D2CED6D2CE8C8E8C949294D6D2CED6
+D2CED6D2CED6D2CED6D2CE949294948E94949294D6D2CED6D2CED6D2CED6D2CED6D2CE9492949492
+94949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CE9492949C969C
+949294D6D2CED6D2CED6D2CED6D2CE9C969C949294D6D2CED6D2CED6D2CED6D2CED6D2CE9496949C
+969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496
+949C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C
+9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C
+9E9C9C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E
+9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5
+A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5
+A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2
+A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6AD
+A5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADA6ADAD
+AAADADA6ADADAAADADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAA
+ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5
+ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5
+AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5B2B5B5AE
+B5B5B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BD
+B6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6
+B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6BDBDBABD
+BDB6BDBDBABDBDB6BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBA
+BDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5
+BDBEBDC5BEC5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5BEC5C5
+C2C5C5BEC5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE000000D6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE84828484828400000084828484828484
+8284FF00008482848482848482840000000000000000000000000000000000000000008482848482
+84848284848284848284D6D2CED6D2CE848284848284848284D6D2CED6D2CE848284848284D6D2CE
+D6D2CE848684D6D2CED6D2CE848284848684D6D2CED6D2CE848284D6D2CED6D2CE8C868C848284D6
+D2CED6D2CE8C868C8486848C868C8486848C868CD6D2CED6D2CE848684D6D2CED6D2CE8C868C8486
+84D6D2CED6D2CE8C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C8A8C8C8A8C8C8A8C
+8C8A8C8C8A8CD6D2CED6D2CE8C8A8C8C8A8CD6D2CED6D2CE8C8A8C8C8A8C8C8A8C8C8E8CD6D2CED6
+D2CE8C8A8C8C8E8CD6D2CED6D2CE8C8A8CD6D2CED6D2CE8C8E8C8C8E8C948E948C8A8C948E94D6D2
+CED6D2CE8C8E8CD6D2CED6D2CE948E948C8E8CD6D2CED6D2CE949294D6D2CED6D2CE8C8E8C949294
+D6D2CED6D2CE8C8E8C9492948C8E8C949294D6D2CED6D2CE8C8E8C949294D6D2CED6D2CE94929494
+9294D6D2CED6D2CE949294949294949294949294949294D6D2CED6D2CE949694D6D2CED6D2CE9492
+94949694D6D2CED6D2CE9492949C969C9492949496949496949C969C9492949C969C9496949C969C
+9496949C969C9496949C969C9496949C969C9496949C9A9C9496949C969C9496949C9A9C9496949C
+9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A
+9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C
+9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA5
+9EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A59C9E9CA5A2A59C9E
+9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5
+A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5
+A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6
+A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAAD
+A5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADAD
+AAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEADADAAADADAEADADAA
+ADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5
+ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5
+B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2
+B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5BDB6BD
+B5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BD
+B6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6
+BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABD
+BDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDC5BEC5BDBABDBD
+BEBDBDBEBDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBE
+BDC5C2C5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5
+BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE000000D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE8482848482
+848482840000008482840000000000008482840000008482840000000000FF0000FF000000FFFF00
+FFFF00000000848284848284848284848284848284D6D2CED6D2CE8482848482848C868CD6D2CED6
+D2CE8482848C868CD6D2CED6D2CE848284D6D2CED6D2CE8C868C848284D6D2CED6D2CE8C868CD6D2
+CED6D2CE8486848C868CD6D2CED6D2CE8486848C868CD6D2CED6D2CED6D2CED6D2CED6D2CE8C8A8C
+D6D2CED6D2CE8486848C8A8CD6D2CED6D2CE8C868C8C8A8C8C8A8C8C8A8CD6D2CED6D2CED6D2CED6
+D2CE8C8A8C8C8A8C8C8A8C8C8A8C8C8A8CD6D2CED6D2CE8C8A8C8C8A8CD6D2CED6D2CE8C8E8C8C8A
+8C948E948C8A8CD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE948E94D6D2CED6D2CE8C8E8C948E94
+D6D2CED6D2CED6D2CED6D2CED6D2CE948E94D6D2CED6D2CE948E94949294D6D2CED6D2CE948E94D6
+D2CED6D2CE949294948E94D6D2CED6D2CE949294949294949294949294D6D2CED6D2CE9492949492
+94D6D2CED6D2CE949294949294D6D2CED6D2CE949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE
+949294D6D2CED6D2CE9C969C949694D6D2CED6D2CE9C969C9496949C969C9496949C969C9496949C
+969C9496949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C9C969C9C9A9C9496
+949C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C
+9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A9CA59EA59C9A9CA5
+9EA59C9A9CA59EA59C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E
+9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5
+A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5
+A2A5A5A2A5A5A6A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6ADA5A2A5ADA6ADA5A2
+A5ADA6ADA5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6AD
+A5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADA6ADAD
+AAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAA
+ADADAEADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5
+ADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5
+AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5B2B5B5AE
+B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BD
+B6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6
+B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6BDBDBABD
+BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBA
+BDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5
+BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE84828442
+4142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2
+CED6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CE8482848482840000FF84828484828484828400000084828484828484828400000000
+00FF0000FF000000FFFF00FFFF00000000848284848284848284848284848284D6D2CED6D2CE8482
+84848284848284D6D2CED6D2CE848684848284D6D2CED6D2CE848684D6D2CED6D2CE8482848C868C
+D6D2CED6D2CE848684D6D2CED6D2CE8C868C848684D6D2CED6D2CE8C868CD6D2CED6D2CE8486848C
+868CD6D2CED6D2CE848684D6D2CED6D2CE8C8A8C848684D6D2CED6D2CE8C8A8C8486848C8A8C8C86
+8C8C8A8C8486848C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8CD6D2CED6D2CE8C8A8C8C8A8C
+D6D2CED6D2CE8C8A8C8C8E8C8C8A8C8C8E8CD6D2CED6D2CE8C8A8C8C8E8C8C8A8C948E948C8A8CD6
+D2CED6D2CE948E94D6D2CED6D2CE8C8E8C948E94D6D2CED6D2CE8C8E8CD6D2CED6D2CE948E948C8E
+8CD6D2CED6D2CE948E94D6D2CED6D2CE8C8E8C949294D6D2CED6D2CE8C8E8C949294948E94949294
+D6D2CED6D2CE949294949294D6D2CED6D2CE949294949294D6D2CED6D2CE949294D6D2CED6D2CE94
+9294949294D6D2CED6D2CE949694D6D2CED6D2CE949294949694D6D2CED6D2CE9492949496949496
+949C969C9492949C969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C
+9496949C969C9496949C9A9C9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A
+9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA5
+9C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA5
+9EA59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5
+A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5AD
+A6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6
+A5ADAAADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADAD
+AEADADAAADADAEADADAAADADAEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAE
+ADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5
+ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2
+B5B5B6B5B5B2B5B5B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BD
+BABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBD
+BDBABDBDBEBDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5
+BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBE
+BDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CE000000000000
+D6D2CED6D2CE000000000000D6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CE8482848482848482840000FF8482840000FF0000FF8482
+840000FF848284000000000084000000000000000000FFFF00000000848284848284848284848684
+848284D6D2CED6D2CE8C868C848284848684D6D2CED6D2CE8482848C868CD6D2CED6D2CE848684D6
+D2CED6D2CE8C868C848684D6D2CED6D2CE8C868CD6D2CED6D2CE8486848C868CD6D2CED6D2CE8486
+84D6D2CED6D2CE8C8A8C848684D6D2CED6D2CE8C8A8CD6D2CED6D2CE8C868C8C8A8CD6D2CED6D2CE
+8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8CD6
+D2CED6D2CE948E948C8A8CD6D2CED6D2CE948E948C8A8C948E948C8A8CD6D2CED6D2CE948E948C8A
+8C948E948C8E8C948E94D6D2CED6D2CE8C8E8CD6D2CED6D2CE948E948C8E8CD6D2CED6D2CE949294
+D6D2CED6D2CE8C8E8C949294D6D2CED6D2CE948E94D6D2CED6D2CE949294948E94D6D2CED6D2CE94
+9294949294949294949294D6D2CED6D2CE949294949294D6D2CED6D2CE949694949294D6D2CED6D2
+CE9C969CD6D2CED6D2CE9492949C969CD6D2CED6D2CE949294D6D2CED6D2CE9C969C949294D6D2CE
+D6D2CE9C969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9C969C9C
+9A9C9496949C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A
+9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9CA59EA5
+9C9A9C9C9E9C9C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9E9CA5
+9EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E
+9CA5A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5
+A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5
+A6A5A5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6
+A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAAD
+ADA6ADADAAADADA6ADADAAADADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADAD
+AAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAA
+ADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5
+ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5
+B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2
+B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BD
+B5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BD
+B6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6
+BDBDBABDBDB6BDBDBABDBDB6BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABD
+BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5
+BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBE
+BDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5
+C5BEC5C5C2C5C5BEC5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000000000000000D6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CE848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6
+D2CE000000000000D6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CE848284424142C5C2
+C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284848284000000848284
+8482848482840000FF84828484828484828400000000000000000000000000000000000000000084
+8284848284848284848284848284D6D2CED6D2CE848284848284848284D6D2CED6D2CE8482848482
+84D6D2CED6D2CE848684848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE
+D6D2CED6D2CE8486848C868C848684D6D2CED6D2CED6D2CED6D2CED6D2CE848684D6D2CED6D2CE8C
+868C848684D6D2CED6D2CE8C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C8A8C8C8A
+8C8C8A8C8C8A8CD6D2CED6D2CED6D2CED6D2CE8C8A8C8C8A8CD6D2CED6D2CED6D2CED6D2CE8C8E8C
+8C8A8CD6D2CED6D2CED6D2CED6D2CED6D2CE8C8A8CD6D2CED6D2CE8C8E8C8C8E8CD6D2CED6D2CED6
+D2CED6D2CED6D2CE8C8E8CD6D2CED6D2CE948E948C8E8CD6D2CED6D2CE9492948C8E8CD6D2CED6D2
+CED6D2CED6D2CED6D2CE8C8E8C9492948C8E8C949294D6D2CED6D2CE8C8E8C949294D6D2CED6D2CE
+949294949294D6D2CED6D2CE949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE949694D6D2CED6
+D2CED6D2CED6D2CED6D2CE9496949492949C969C9492949496949496949C969C9492949C969C9496
+949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9496949C969C9496949C9A9C
+9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A
+9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E9CA59EA5
+9C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A59C9E9CA5
+A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5
+A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6
+A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEADADAAADAD
+AEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAE
+ADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5
+ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2
+B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BD
+BABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDC5BEC5
+BDBABDBDBEBDBDBEBDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5
+BEC5BDBEBDC5C2C5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BE
+C5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CE000000000000000000
+000000000000000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE00000000
+0000000000000000000000000000000000000000000000D6D2CED6D2CE848284424142C5C2C5C5C2
+C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE84
+82848482848482840000008482840000000000008482840000008482840000008482848482848482
+848482848482840000008482848482848482848482848482848486848482848482848482848C868C
+8482848486848482848C868C8482848C868C8482848C868C8486848C868C8482848C868C8486848C
+868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C8C868C8C8A8C8486
+848C8A8C8C868C8C8A8C8486848C8A8C8C868C8C8A8C8C868C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C
+8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8A8C8C8A8C948E948C8A8C8C
+8E8C8C8A8C948E948C8A8C948E948C8A8C948E948C8E8C948E948C8A8C948E948C8E8C948E948C8E
+8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C949294948E949492948C8E8C949294
+948E949492948C8E8C949294948E94949294948E9494929494929494929494929494929494929494
+92949492949492949492949492949492949496949492949492949492949C969C9492949496949492
+949C969C949294D6D2CED6D2CE9C969C9496949C969C9492949C969C9496949C969C9496949C969C
+9496949C969C9496949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C9C969C9C
+9A9C9496949C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A
+9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A9CA59EA5
+9C9A9CA59EA59C9A9CA59EA59C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5
+9EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E
+9CA5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5
+A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6ADA5A2A5AD
+A6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6
+A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAAD
+ADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADAD
+AAADADAAADADAEADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5AEB5ADAA
+ADB5AEB5ADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5
+ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5AEB5B5
+B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2
+B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BD
+B5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BD
+B6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBDBABDBDB6
+BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABD
+BDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5
+BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBE
+BDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BEC5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142C5C2C5C5C2C5FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CE848284848284848284848284848284848284000000848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848486848482848486848482848486848482848486848482
+848C868C8482848486848486848C868C8482848C868C8486848C868C8486848C868C8486848C868C
+8486848C868C8486848C8A8C8486848C868C8486848C8A8C8486848C8A8C8486848C8A8C8486848C
+8A8C8C868C8C8A8C8486848C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C948E94
+8C8A8C8C8E8C8C8E8C948E948C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C94
+8E948C8E8C9492948C8E8C948E948C8E8C9492948C8E8C9492948C8E8C9492948C8E8C949294948E
+949492948C8E8C949294949294949294949294949294949294949294949294949294949294949294
+949294949294949294949694949294949694D6D2CED6D2CE9492949496949492949C969C94929494
+96949496949C969C9492949C969C9496949C969C9496949C969C9496949C969C9496949C969C9496
+949C9A9C9496949C969C9496949C9A9C9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C
+9496949C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E
+9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5
+9C9E9CA59EA59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5
+A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6AD
+A5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5AD
+A6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAA
+ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEAD
+ADAAADADAEADADAAADADAEADADAAADADAEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5
+AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAE
+ADB5B2B5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5
+B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6
+B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABD
+B5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBA
+BDBDBEBDBDBABDBDBEBDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5
+BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5
+C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5FFFFFF848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284424142FFFFFF84828484828484828484828484828484828484828484828484828484
+8284848284848284848284848284424142C5C2C5C5C2C5FFFFFF8482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284424142C5C2C5C5C2C5D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE84828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+848486848482848482848482848C868C8482848486848482848C868C8482848C868C8482848C868C
+8486848C868C8482848C868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C
+868C8486848C8A8C8C868C8C8A8C8486848C8A8C8C868C8C8A8C8C868C8C8A8C8C868C8C8A8C8C86
+8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C
+8C8A8C8C8A8C8C8A8C948E948C8A8C8C8E8C8C8A8C948E948C8A8C948E948C8A8C948E948C8E8C94
+8E948C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E
+8C949294948E949492948C8E8C949294948E94949294948E94949294948E94949294948E94949294
+94929494929494929494929494929494929494929494929494929494929494929494969494929494
+92949492949C969C9492949496949492949C969C9492949C969C9492949C969C9496949C969C9492
+949C969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C
+9C969C9C9A9C9496949C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A
+9CA59EA59C9A9C9C9E9C9C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA59C9A9CA59EA5
+9C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5
+A2A59C9E9CA5A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5ADA6AD
+A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A2A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADADA6ADADAAADA5A6
+A5ADAAADADA6ADADAAADADA6ADADAAADADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADB5AEB5ADAAADAD
+AEADADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAE
+ADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5
+B5AEB5B5B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2
+B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBD
+BABDBDB6BDBDBABDBDB6BDBDBABDBDB6BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5
+BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5
+BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BE
+C5C5C2C5C5BEC5C5C2C5C5BEC5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C542414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142C5C2C5C5C2C5424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+4142C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE8482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848486848482848486848482848486848482848486848482848C868C8482848486848486
+848C868C8482848C868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C
+8486848C868C8486848C8A8C8486848C8A8C8486848C8A8C8486848C8A8C8C868C8C8A8C8486848C
+8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C8C8E8C8C8A8C948E948C8A8C8C8E8C8C8E8C948E94
+8C8A8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C9492948C8E8C94
+8E948C8E8C9492948C8E8C9492948C8E8C9492948C8E8C949294948E949492948C8E8C9492949492
+94949294949294949294949294949294949294949294949294949294949294949294949294949694
+9492949496949492949496949492949496949492949C969C9492949496949496949C969C9492949C
+969C9496949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9496949C969C9496
+949C9A9C9496949C9A9C9496949C9A9C9496949C9A9C9C969C9C9A9C9496949C9A9C9C9A9C9C9A9C
+9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C
+9E9C9C9A9C9C9E9C9C9A9C9C9E9C9C9A9CA59EA59C9A9C9C9E9C9C9E9CA59EA59C9A9CA59EA59C9E
+9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A59C9E9CA59EA59C9E9CA5A2A5
+9C9E9CA5A2A59C9E9CA5A2A59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A5A2A5A5A2A5A5A2A5A5
+A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A6A5A5A2
+A5A5A6A5A5A2A5A5A6A5A5A2A5ADA6ADA5A2A5A5A6A5A5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6AD
+A5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5AD
+AAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6A5ADAAADADAAADADAAADADAAADADAAADADAA
+ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAEADADAAADADAEADADAAADADAEAD
+ADAAADADAEADADAAADB5AEB5ADAAADADAEADADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5
+AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAE
+ADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5
+B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5B6B5B5B2B5B5
+B6B5B5B2B5BDB6BDB5B2B5B5B6B5B5B6B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6
+B5BDB6BDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABD
+B5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBD
+BABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBABDBDBEBDBDBA
+BDC5BEC5BDBABDBDBEBDBDBEBDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5
+BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5
+C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CE84828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848486848482848482848482
+848C868C8482848486848482848C868C8482848C868C8482848C868C8486848C868C8482848C868C
+8486848C868C8486848C868C8486848C868C8486848C868C8486848C868C8486848C8A8C8C868C8C
+8A8C8486848C8A8C8C868C8C8A8C8486848C8A8C8C868C8C8A8C8C868C8C8A8C8C8A8C8C8A8C8C8A
+8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8A8C8C8E8C8C8A8C8C8A8C8C8A8C948E94
+8C8A8C8C8E8C8C8A8C948E948C8A8C948E948C8A8C948E948C8E8C948E948C8A8C948E948C8E8C94
+8E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C948E948C8E8C949294948E949492948C8E
+8C949294948E949492948C8E8C949294948E94949294948E94949294949294949294949294949294
+9492949492949492949492949492949492949492949496949492949492949492949C969C94929494
+96949492949C969C9492949C969C9492949C969C9496949C969C9492949C969C9496949C969C9496
+949C969C9496949C969C9496949C969C9496949C969C9496949C9A9C9C969C9C9A9C9496949C9A9C
+9C969C9C9A9C9496949C9A9C9C969C9C9A9C9C969C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C
+9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9A9C9C9E9C9C9A9C9C9A9C9C9A9CA59EA59C9A9C9C9E9C9C9A
+9CA59EA59C9A9CA59EA59C9A9CA59EA59C9E9CA59EA59C9A9CA59EA59C9E9CA59EA59C9E9CA59EA5
+9C9E9CA59EA59C9E9CA59EA59C9E9CA59EA59C9E9CA5A2A5A59EA5A5A2A59C9E9CA5A2A5A59EA5A5
+A2A59C9E9CA5A2A5A59EA5A5A2A5A59EA5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2A5A5A2
+A5A5A2A5A5A2A5A5A2A5A5A2A5A5A6A5A5A2A5A5A2A5A5A2A5ADA6ADA5A2A5A5A6A5A5A2A5ADA6AD
+A5A2A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A2A5ADA6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5AD
+A6ADA5A6A5ADA6ADA5A6A5ADA6ADA5A6A5ADAAADA5A6A5ADAAADA5A6A5ADAAADADA6ADADAAADA5A6
+A5ADAAADADA6ADADAAADADA6ADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAADADAAAD
+ADAAADADAAADADAAADADAEADADAAADADAAADADAAADB5AEB5ADAAADADAEADADAAADB5AEB5ADAAADB5
+AEB5ADAAADB5AEB5ADAEADB5AEB5ADAAADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAEADB5AEB5ADAE
+ADB5AEB5ADAEADB5AEB5ADAEADB5B2B5ADAEADB5B2B5ADAEADB5B2B5B5AEB5B5B2B5ADAEADB5B2B5
+B5AEB5B5B2B5B5AEB5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5
+B2B5B5B2B5B5B2B5B5B2B5B5B2B5B5B2B5BDB6BDB5B2B5B5B6B5B5B2B5BDB6BDB5B2B5BDB6BDB5B2
+B5BDB6BDB5B2B5BDB6BDB5B2B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BDB5B6B5BDB6BD
+B5B6B5BDB6BDB5B6B5BDBABDB5B6B5BDBABDB5B6B5BDBABDBDB6BDBDBABDB5B6B5BDBABDBDB6BDBD
+BABDBDB6BDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBABDBDBA
+BDBDBABDBDBABDBDBABDBDBABDC5BEC5BDBABDBDBEBDBDBABDC5BEC5BDBABDC5BEC5BDBABDC5BEC5
+BDBABDC5BEC5BDBABDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5BEC5BDBEBDC5
+BEC5BDBEBDC5C2C5BDBEBDC5C2C5BDBEBDC5C2C5C5BEC5C5C2C5BDBEBDC5C2C5C5BEC5C5C2C5C5BE
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5
+C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2
+C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5
+C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5C5C2C5D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284848284848284D6D2CE848284D6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284D6D2CED6D2CED6D2CE848284
+848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482848482
+84848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2
+CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284D6
+D2CED6D2CED6D2CE848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284D6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CE84828484828484
+8284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6D2CE848284848284848284
+D6D2CED6D2CE848284848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84848284848284D6D2CED6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CE848284848284
+848284D6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE8482
+84848284848284D6D2CED6D2CE848284848284848284848284D6D2CED6D2CE848284D6D2CED6D2CE
+848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CE8482848482
+84848284D6D2CED6D2CE848284D6D2CE848284848284848284848284D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284848284848284848284848284D6D2CE848284D6D2CE848284D6D2
+CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6
+D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6
+D2CE848284D6D2CED6D2CED6D2CE848284D6D2CE848284848284D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6
+D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284848284848284848284
+D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE84
+8284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE
+848284D6D2CE848284D6D2CE848284848284848284848284848284D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CE848284D6D2
+CED6D2CE848284D6D2CED6D2CE848284848284848284848284D6D2CE848284D6D2CED6D2CED6D2CE
+848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284848284D6D2CED6D2CE8482
+84D6D2CE848284D6D2CED6D2CE848284848284848284848284848284D6D2CE848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE848284848284848284848284D6D2CE848284D6D2
+CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284848284848284848284848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6
+D2CED6D2CED6D2CE848284D6D2CE848284848284848284848284848284D6D2CE848284D6D2CE8482
+84D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6
+D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+D6D2CED6D2CE848284D6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CE84
+8284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE
+848284D6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE
+848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CE
+D6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2
+CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE84
+8284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE848284D6D2
+CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CE84
+8284D6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CE848284D6D2
+CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6
+D2CED6D2CED6D2CE848284D6D2CE848284D6D2CE848284D6D2CED6D2CED6D2CE848284D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE84
+8284D6D2CED6D2CE848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CE848284
+D6D2CED6D2CE848284848284848284848284D6D2CE848284848284848284848284D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482848482
+84848284848284D6D2CED6D2CE848284848284848284848284D6D2CED6D2CED6D2CE848284D6D2CE
+D6D2CED6D2CED6D2CE848284848284848284D6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84D6D2CED6D2CED6D2CED6D2CE848284848284848284848284D6D2CE848284848284848284848284
+D6D2CED6D2CE848284D6D2CED6D2CE848284848284848284D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2
+CE848284D6D2CED6D2CE848284848284848284D6D2CED6D2CE848284D6D2CE848284848284848284
+848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000000000000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000000000D6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE00000094929494929494929494929494
+9294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE9492949492
+94949294949294000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE737173737173737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE0000009492
+94D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFFFFFFFFFFFFFF737173D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE737173737173FFFFFF737173737173D6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CEFF
+FFFFFFFFFF848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284D6D2CE8482848482
+84D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF737173D6D2CED6D2CED6D2CE737173737173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73
+7173D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284D6D2CEFFFFFF848284D6D2CED6D2CE848284D6D2CED6D2CED6D2CE848284848284D6D2CE
+FFFFFF848284D6D2CE848284848284D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE949294000000DEDBDEFFFFFFFFFFFFD6D7D6000000949294D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294000000DEDBDEFFFFFFFFFFFFD6D7D600000094
+9294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CE000000949294D6D2CED6D2CE0000000000000000000000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CE
+000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE737173FF
+FFFF000000000000000000000000FFFFFFFFFFFF737173737173737173FFFFFF0000000000000000
+00000000FFFFFFFFFFFF737173D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284D6D2CE848284848284848284848284D6D2CED6D2CE84828484828484
+8284D6D2CE848284848284848284D6D2CE848284D6D2CE848284FFFFFFD6D2CED6D2CED6D2CE8482
+84424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF949294949294FFFFFFFFFFFF000000
+949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF9492
+94949294FFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000949294D6D2CED6D2CE
+000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000
+0000949294D6D2CED6D2CE000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CE737173FFFFFF000000000000000000949294949294FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000000000000000949294FFFFFF737173D6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFF848284848284848284848284FFFF
+FFD6D2CE848284FFFFFFFFFFFFFFFFFF848284848284848284848284D6D2CEFFFFFF848284FFFFFF
+D6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000DEDBDEFFFFFF949294FFFFFFFF
+FFFFFFFFFFFFFFFFDEDBDE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000
+DEDBDEFFFFFF949294FFFFFFFFFFFFFFFFFFFFFFFFDEDBDE000000D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294949294949294D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CE949294D6D2CED6D2CE000000000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE000000000000000000949294D6D2CED6D2CED6D2CE949294D6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFF000000000000000000949294FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000949294FFFFFF737173D6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284
+848284848284848284FFFFFF848284848284FFFFFFD6D2CED6D2CE848284848284848284848284FF
+FFFFD6D2CE848284FFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294949294949294949294000000000000D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFF
+FF949294FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE000000FFFFFF949294FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000009492
+94D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294949294000000D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000D6D2CE949294000000949294D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFF0000009492
+94949294000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF949294000000949294
+FFFFFF737173D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CE848284FFFFFF848284848284848284848284848284D6D2CE848284FFFFFFD6D2CED6D2CED6D2
+CE848284848284848284848284D6D2CE848284FFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000949294949294D6D2CED6D2
+CED6D2CE000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE0000
+00949294D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294D6
+D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CE949294D6D2CED6D2CE949294D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+737173FFFFFFFFFFFF949294FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF94
+9294FFFFFFFFFFFF949294FFFFFF737173D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFF848284848284FFFFFFFFFFFFD6D2CE
+848284848284848284D6D2CED6D2CEFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFD6D2CED6D2CED6
+D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294D6D2CED6D2CED6D2CED6D2CE000000
+949294D6D2CED6D2CED6D2CED6D2CE000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000DEDBDEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFDEDBDE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000DEDBDEFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFDEDBDE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CE
+D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CED6D2CE949294D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF949294FFFFFFFFFF
+FFFFFFFFFFFFFF949294FFFFFFFFFFFFFFFFFFFFFFFF737173D6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CEFF
+FFFFFFFFFFD6D2CED6D2CED6D2CEFFFFFFFFFFFF848284D6D2CED6D2CED6D2CED6D2CE848284D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6
+D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CED6D2CE000000000000949294D6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000
+000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF737173D6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE
+D6D2CED6D2CE848284FFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000
+00000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000
+949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000DEDBDEFFFFFFFFFFFFDEDBDE000000949294949294D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000000000000000DEDBDEFFFFFFFFFFFFDEDBDE00000094929494
+9294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000000000949294949294949294949294000000949294949294
+949294949294000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE737173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284848284848284848284FFFFFFD6D2CED6D2CED6D2CED6D2CE8482844241
+42D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000949294D6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000000000000000949294000000000000000000000000949294949294D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000009492940000000000000000
+00000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6
+D2CE000000949294D6D2CED6D2CED6D2CE000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE737173737173FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CEFFFFFFFFFFFF848284FFFFFFD6D2CED6D2CE
+D6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000949294D6D2CED6D2
+CED6D2CED6D2CED6D2CE000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000000000000000
+0000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294949294D6D2CE94929494929494
+9294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294
+949294D6D2CE949294949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE949294D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF737173D6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CEFFFFFF848284D6D2CED6D2CED6D2CED6D2CE848284848284D6D2CEFFFFFFD6D2CED6D2CE84
+8284FFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000
+000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00000000000000000000000000000000949294D6D2CED6D2CED6D2CED6D2CE000000949294D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294949294D6D2
+CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000
+0000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CE949294D6D2CE
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2
+CE000000D6D2CE949294FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFF737173
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284848284D6D2CEFFFFFFFFFF
+FFD6D2CED6D2CED6D2CE848284FFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000000000000000000000949294D6D2CED6D2CED6D2CED6D2CE0000000000009492
+94D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000000000000000000000000000000000000000D6D2CED6D2CED6D2CED6
+D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000
+949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2D6D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000
+00000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000D6
+D2CE949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000000000000000D6D2CE949294D6D2CE737173FFFFFFFFFFFFFFFFFFFFFFFF00000000
+0000000000949294737173D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284848284848284848284D6D2CED6D2CED6D2CE848284D6D2CE
+FFFFFFFFFFFF848284848284848284848284D6D2CE848284FFFFFFD6D2CED6D2CED6D2CED6D2CE84
+8284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE000000000000000000000000000000000000000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CE949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000009492940000000000000000
+00949294D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000949294949294D6D2CED6D2CED6D2CED6D2CE0000000000000000000000000000
+00000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CE00
+0000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2
+CE000000000000000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000
+000000949294D6D2CED6D2CE000000D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000949294D6D2CED6D2CED6D2CE737173FFFF
+FFFFFFFFFFFFFF000000000000000000949294737173D6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284848284848284848284D6
+D2CED6D2CE848284848284D6D2CED6D2CE848284848284848284848284848284848284FFFFFFD6D2
+CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000000094929400000000000000
+0000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294
+949294D6D2CE000000000000000000D6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE949294000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE000000
+000000000000000000000000000000D6D2D6D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294000000949294949294D6D2CED6D2
+CED6D2CED6D2CED6D2CE000000000000000000000000000000000000D6D2D6D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+000000949294D6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000000000000000949294D6D2CED6D2CE000000949294D6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2CE
+D6D2CED6D2CED6D2CE737173FFFFFF000000000000000000000000949294737173D6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84848284848284848284FFFFFFD6D2CED6D2CE848284848284D6D2CE848284848284848284848284
+FFFFFF848284FFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000009492
+94949294D6D2CE000000000000000000D6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CE000000949294949294D6D2CED6D2CED6D2CE949294000000949294D6D2CE0000000000000000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2D6000000000000D6D2D6D6D2D6D6D2D6D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294
+949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2D6D6D2D6D6D2D6D6D2D6D6D2D6D6
+D2D6D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CE949294949294949294949294D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE949294949294949294949294D6D2CED6D2CE000000949294
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE94
+9294949294949294949294D6D2CED6D2CED6D2CED6D2CE737173FFFFFF9492949492949492949492
+94737173D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284D6D2CE848284848284848284FFFFFFD6D2CED6D2CED6D2CE84828484828484
+8284848284848284848284FFFFFF848284FFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000949294949294D6D2CED6D2CED6D2CE949294000000949294D6D2CED6D2CE00000000
+0000949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CED6D2CED6D2CE949294949294
+D6D2CED6D2CE949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2D6D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE737173FFFFFF
+FFFFFF737173737173737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CE848284D6D2CEFFFFFF848284FFFFFFD6D2CED6D2
+CED6D2CED6D2CE848284FFFFFF848284848284848284848284D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+D6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE9492
+94D6D2CED6D2CED6D2CE949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2D6D6D2D6D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000949294D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE737173737173D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284D6D2CEFFFFFFD6D2CE
+D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE848284848284FFFFFFFFFFFFFFFFFF848284D6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CE000000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000000000949294D6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFFFFF
+FFD6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CE949294949294949294949294949294949294D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE9492949492949492949492949492
+94949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CEFFFFFF8482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284848284848284848284848284848284424142FF
+FFFF8482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284424142FFFFFF84828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284424142FFFFFF848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284848284848284848284848284848284848284848284848284848284424142FFFF
+FF848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284424142FFFFFF8482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CEFFFFFF8482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284424142FFFFFF84828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284424142D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+4142424142424142424142424142424142424142424142424142424142424142424142D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+4142424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284FFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+4142424142424142424142424142D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE08960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE84828442414284828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5AFFFFFFFFFFFFFFFFFF5A5D5AD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6
+D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5AFFFFFFFFFFFFFFFF
+FF5A5D5A000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CE00
+0000D6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CE000000D6D2CE0000
+00000000D6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CE000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+5A5D5AFFFFFFFFFFFFFFFFFF5A5D5A9492949492949492949492945A5D5AD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+0896000896000896000896000896000896000896000896000896000896000896005265E608960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2
+CED6D2CED6D2CE000000000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CE000000000000D6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE00000000
+0000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE5A5D5AFFFFFFFFFFFFFFFFFF5A5D5A9492949492949492949492945A5D
+5AD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E6089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2
+CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000
+D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6
+D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2
+CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5AFFFFFFFFFFFFFFFFFF5A5D5A949294
+9492949492949492945A5D5AD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFF
+D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000
+0000000000000000000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2
+CE000000000000000000000000000000000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000
+D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5A5A5D5A5A
+5D5A5A5D5A5A5D5A9492949492949492949492945A5D5AD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+000896000896000896000896000896000896000896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+D6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6
+D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE5A5D5A9492949492949492949492949492949492949492945A5D5AD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE00
+0000D6D2CED6D2CED6D2CE000000000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5A94929494929494929494929494929494929494
+92945A5D5AD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+0896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E60896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6
+D2CED6D2CE000000000000000000000000000000000000D6D2CED6D2CE0000000000000000000000
+00D6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CE000000D6D2CED6D2CED6D2CE000000
+000000000000000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CE000000000000000000D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE5A5D5A5A5D5A5A5D5A5A5D
+5A5A5D5A5A5D5A5A5D5A5A5D5A5A5D5AD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+0896000896000896000896000896000896000896000896000896000896000896000896005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482
+84FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E60000000000005265E60000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896
+000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960000000008960008960052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000000000000000
+00000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E6089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600
+0896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E608960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E60000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E60000000000000000000000000000005265E60000000000
+0000000000E30000E3000000000000000000000000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600089600089600D6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6
+D2CE0896000896000896000896000896000896000896000896000896000896005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E60000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000E700000000
+00000000000000000000000000000000000000000000000000000000DF000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442
+4142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284FFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600089600089600
+0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000000000000E30000000000000000000000000000E30000DF0000E30000E30000DF0000DF000000
+000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CE848284424142848284FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008
+96000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E600000000000000E70000000000E30000E30000E30000E70000CE0000E700
+00DF0000DF0000DF000000000000005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284848284848284FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896
+000896000896000896000896000896000896000896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E600000000000000000000DF0000DF0000E30000
+CA0000E30000BA0000E70000CA0000CE0000DF000000000000000000000000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E60000000000000000005265E65265E65265E60000000000000000005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CED6D2CE0896000896000896000896000896000896000896000896000896000896005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E60000000000005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+0000E30000E70000DF0000CA0000E30000BA0000C20000BA0000D200000000000000000000000000
+0000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E60000000000000000000000000000000000000000000000
+000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+84828442414284828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284848284848284848284848284848284848284D6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896
+000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000CE000000000000
+000000000000005265E60000000000005265E60000000000000000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E600000000000000CA0000CA0000CA0000C20000D20000B60000E30000E30000000000
+000000E70000E70000C20000000000CA0000A6000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000E70000DF0000D200
+0000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E6089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CE848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600
+0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000000000
+000000000000000000000000FFFF00FFFF0000000000000000BA000000005265E600000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E600000000000000C20000CA0000CE0000BE0000B60000C2
+0000BA0000A60000000000000000C20000E70000000000BE0000DB0000D2000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+000000AA0000CA0000AA000000005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08
+96000896000896000896000896000896000896000896000896005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000008960000000000000000D200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000000000
+000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000D200
+00CA0000BE0000D20000BE0000BA0000000000AA0000000000B60000C20000D70000000000D20000
+CE0000C2000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6000000000000089A0000AA000000000000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E600000000000000DF0000AA00000000FFFF00FFFF00FFFF00FFFF00
+FFFF0000000000000000CA0000000000DB000000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000000000000000000DF0000E30000D20000E70000AA0000A60000000000BE0000A60000000000C2
+00009E0000000000000000B2000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E60000000000000000000000000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424142FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008
+96000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000000000FFFF00FF
+FF00FFFF00FFFF00000000000000FFFF00FFFF00000000000000089A000000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E600000000E300000000009E0000C20000000000000000000000CA00
+00AE0000DF0000000000C20000D20000CA0000C2000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E6000000000000089A000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896
+000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E60000
+0000E300000000FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+00CA000896000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E600000000000000000000000000000000
+A60000000000AE00009E0000C600009E0000DB000000000000000000000000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000000000
+0000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE0896000896000896000896000896000896000896000896000896005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000
+089A00000000000000009E0000D700000000000000FFFF00FFFF00000000FFFF00FFFF00FFFF00FF
+FF0000000000000000000000AA0000AA000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+0000000000E30000E70000BE0000000000CA0000D20000BA0000CA0008960000000000000000C600
+0000000000000000000000005265E65265E65265E65265E65265E65265E600000000000000000000
+000000000000DF0000000000000000CA000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000AA0000A20000D200000000FFFF00000000FFFF
+00FFFF00FFFF00000000000000FFFF00FFFF0000000000000000C6000000000000000000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E600000000000000C20000000000000000C20000C60000DB0000BE0000C60000
+D700089A0000D70000BA0000000000AA000000000000005265E65265E65265E65265E65265E65265
+E600000000E70000000000E30000E30000000000CE0000C6000000000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E6089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000000000000000000000D6D2
+CED6D2CE313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600
+0896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000000000
+000000000000000000FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000
+B2000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E60000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E600000000DF0000000000DF00089A0000D2
+0000C20000DB0000D200089A0000B60000DB0000C20000CE00000000000000000000000000000000
+0000005265E65265E65265E600000000000000E30000000000000000000000B60000D200009E0000
+9E000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294949294949294949294949294
+949294949294000000000000000000313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008
+96000896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E60000000000005265E65265E65265E65265E6000000FFFF00000000FFFF00000000000000FFFF
+00FFFF00FFFF000000000000000000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000
+00CA0000DB0000CA0000CE0000B60000B60000C20000C20000CE0000AA00089A0000BA0008960000
+00000000000000000000000000005265E65265E65265E60000000000000000000000000000000000
+0010920010920000CE000000005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000000000000000000000000000000000000000000000000000D6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000000000000000000000000000000000
+00000000000000D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000000000000000
+0000000000000000000000000000000000000000D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000000000000000000000000000000000000000000000000000000000000000D6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000094929494929494
+9294949294949294949294949294949294949294949294949294313131D6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000
+000000FFFF00FFFF00000000000000FFFF00FFFF000000000000005265E60000000000005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E600000000E70010920000B60000AA0000D700009E0000CE0000D20000D700009E0000CE0000A2
+0000D70000000000000000000000E70000CA000000000000000000000000005265E65265E6000000
+00000000D70000000000000000B200009E000000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CE
+D6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00949294949294949294949294949294949294949294949294949294949294949294949294313131
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008
+96000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+0000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF000000000000000000
+000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E600000000000000CE0000C60000B60000AE0000AE0000AE0000CA0000CE00
+009E0000000000000000000000000000000000AE0000000000BE0000BE0000B60000000000DF0000
+000000000000000000000000000000B60000000000000000A2000000000000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE00000000000000000000
+0000000000000000000000D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000000000000000
+00000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000
+0000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE00000094929494929400000094929494929494929494929494929494929494929494
+9294949294949294313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896
+000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+00000000000000000000000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+00000000B6000000000000000000000000000000000000000000000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E60000000000000000000000000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E600000000000000000000DF0000AA0000CE0000CE0000
+B60000D70000DB0000000000000000B60000000000B20000CA0000A20000CE0000000000AE0000D2
+0000000000000000000000000000000000000000CA0000D700000000000000000000000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000D6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CE0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000
+000000000000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE00
+00000000000000000000000000000000009492949492940000009492949492940000009492949492
+94949294949294949294949294949294949294313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+0896000896000896000896000896000896000896000896000896005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+00000000FFFF00FFFF000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E600000000000029860000A600089A00000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF0000000029860000AE0000D20000DB0000DB0000000000CE000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000089A0000D70000
+C6000000005265E65265E65265E65265E65265E65265E600000000000000000000000000000000C2
+0000B60000AA0000D70000000000000000000000D70000DF0000B60000A20000DF0000B60000CA00
+00B60000000000000000000000000008960000BE0000BE0000000000000000D20000C20000D20000
+00000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000D6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE
+D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000
+0000000000000000000000000000000000000000000000000000000000000000000000000000D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF313131000000949294949294000000949294949294
+000000949294949294000000949294949294949294949294949294949294313131D6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000000000000052
+65E65265E65265E65265E65265E65265E65265E60000000000003A7D00318200009E00000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000003A7D00218A00089A0000DB00109200
+0000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E60000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+00089A0000AE0000D70000B2000000005265E65265E65265E65265E65265E6000000000000000000
+00000019BA4A00000000000000D700009E0000000000A20000A20000CE0000AA0000CE0000B20010
+920000BE0000C20000D200089A0000D70000000000CA0000CA0000D70000CA0000CA0000000000E3
+000000000000000000000000000000000000000000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFF
+000000D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CE000000D6D2CED6D2CED6D2CE0000000000000000000000000000000000000000000000000000
+00000000000000FFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF00000000000000000000000000
+0000000000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF
+FFFFFF000000000000000000000000000000000000000000000000000000000000000000D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF00000094929494929400
+00000000009492940000009492949492940000009492949492949492949492949492940000000000
+00313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600
+0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000
+000000000000000896000000005265E65265E65265E65265E65265E65265E600000000000000BA00
+298A00298600089A00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000031820031820029
+8600089A0010920000D20000B60000000000000000B2000000000000005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E600000000000000000000000000BA000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E60000000000000000000000000000000000005265E60000
+005265E60000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E600000000000000D20008960000C60000AA0000AE000000000000005265E600000000000000
+000000000000000000000000E70000E30000E30000000000E70000000000D70000DF0000C6001092
+0000A60000DB0000DF0000B20000B20000BE0008960000CA0000D70000000000C20000C60000CA00
+009E0000D70000000000D20000DB0000CE00009E0000AE000000000000000000005265E65265E652
+65E65265E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000000000000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000D6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000
+000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000
+00000000000000000000000000000000000000000000D6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CE000000000000000000000000FFFFFFFFFFFF000000000000000000000000FF
+FFFF000000000000FFFFFFFFFFFF000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000D6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFF0000
+00949294949294000000FFFFFFFFFFFF000000949294949294000000949294949294000000000000
+000000000000000000949294313131D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008
+96000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000089A000000000000000000005265E65265E65265E65265E652
+65E65265E6000000000000109200298600199200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+000000003A7D0042790042790829860000A20000DB0000B60000DB00000000089A00089A00000000
+0000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E600000000000008960000000000C2000000000000
+000000000000005265E65265E65265E65265E65265E65265E6000000109200000000218A00000000
+0000000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E600000000000000D70000CA0000B60000A60000B6000000
+0000000000D20000000000000019BA4A00000019BA4A00E30000E30000E70000000000000000D200
+00AA0000CE00009E0010920000AE0000AA0000CA0000A20000DB0000DB0000CE0008960000000000
+000000B20000000000000000D70000000000000000D20000D20000DB00009E0000C60000A60000E3
+000000005265E65265E65265E65265E65265E60000000000000000000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000D6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000FFFFFFFFFFFF0000000000
+00000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000000000D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CE000000FFFFFF000000949294000000FFFFFFFFFFFFFFFFFFFFFFFF00000000000094929494
+9294000000FFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE0896000896000896000896000896000896000896000896000896005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000DB002986000000000000
+005265E65265E65265E65265E65265E65265E65265E6000000000000000000000000000000000000
+FFFF00FFFF000000000000003182003A7D00298600318200427900198E0000C60000A20000D20000
+000000B20000AE0000CE000000000000005265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000109200000000000000
+00000042790000000000000000C6000000005265E65265E65265E65265E65265E65265E600000000
+0000000000198E0000BE0000000000D70029860000AE0000D2000000005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000000000DB0000CE00
+00C60000B20000000000000000000000000000000000000000E30000000000000000E30000E30000
+E70000000000E300009E0000A20000D70000DB00089A0000CE0000BE0000C600089A0000AA0000B6
+00089A0000A600000000000000000000FFFF00FFFF0000000000000000A600009E0000CA00009E00
+00C20000C600089A0000CA000000000000000000000000000000005265E600000000CE0000DB0000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000
+000000000000000000000000000000000000000000000000000000FFFFFF000000D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2
+CED6D2CED6D2CE000000000000000000000000000000000000000000000000000000000000000000
+FFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CE000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CE00000000000000000000000000000000000000000000
+0000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000000000FFFFFFFFFFFF
+FFFFFFFFFFFF000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CE000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000949294D6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008
+96005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+00000000FFFF00FFFF00000000000000FFFF00FFFF00FFFF00FFFF00FFFF00000000000000298600
+00A60000000000CE00218A000000005265E65265E65265E65265E65265E65265E65265E600000000
+0000000000000000000000000000000000109200198E003A7D0000C60000B200198E003182004279
+0010920000A60000000008960000CE0000B20000AA000000005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000000000000000000000000BE00218A0000000000DF0000CE0000BE000000005265E65265E65265
+E65265E65265E65265E60000003A7D0000B200198E0000DB00000000218E00089600000000000000
+0000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+D20000DB0000000000000000000000B20000C20000000000E30000BE0000CA000000000000000000
+0000E30000E30000E70000DF0000000000CA0000AA0000DB00009E0000A20000C20000D20000A600
+00AE0000DF0000D200000000000000109600000000000000FFFF00FFFF00FFFF00FFFF00FFFF0000
+000000C20000C20000CA0000000000000000BA0000DF0000BE0000DF0000E70000CA000000000000
+000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000D6D2CED6D2CE000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000D6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000000000000000000000D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE00
+0000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000
+00000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000949294D6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000949294D6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF313131313131
+313131313131FFFFFFFFFFFF313131313131313131313131313131313131313131FFFFFFFFFFFF00
+0000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896
+000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FF
+FF00000000000000000000089A000000000000000000000000000000000000005265E65265E65265
+E65265E65265E65265E65265E600000000000000000000E70000AA00218A00218E0000CE0000BA00
+009E00218E002986003182003A7D0000000000B20000BE0000A20000CE0000B20000000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E60000000000000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E6000000000000109200298600000000218E002986000000003A7D00009E00000000
+0000000000005265E65265E65265E65265E65265E6000000199200198E0042790000000000000029
+86002986003A7D0000000000BE000000005265E65265E65265E65265E65265E65265E65265E65265
+E65265E600000000000000D70000B20000AE00198E00198E0000000000000000000000E30000E700
+00E30000C20000E30000000000000000000000E30000E30000000000A60000BE0000B60000DB0000
+A60000A20010920010920000BA00000000000000FFFF00FFFF00000000000000FFFF000000000000
+00FFFF00FFFF00FFFF0000000000C200000000000000FFFF00FFFF0000000000000000D20000AE00
+00C60000C20000BA0000000000BA0000C20000000000D2000000000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FF000000D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000D6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CED6D2CE000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000
+000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000949294949294D6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE000000000000000000000000D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000
+000000949294949294D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FF
+FFFFFFFFFF313131FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+0896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000
+00FFFF00FFFF00000000000000009E0000000000000000A200198E00089A00109200000000000000
+0000000000005265E65265E65265E65265E65265E65265E60000005265E600000000000000C20000
+A60000000000E30000DB00218A00009E003A7D00298600318200000000089A0000AE0000C20000D7
+00009E0000B6000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E60000000000000000000000000000000000005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E600000000000000000000000000CA0000CE0000000000000000000010
+9600198E00218A0000000000D7001092000000005265E65265E65265E65265E60000002986001092
+0042790000000000D70000AA003A7D0042790000000000D7000896000000000000005265E65265E6
+5265E65265E65265E65265E65265E600000000D70010920000A60000AA0029860029860029860010
+960000000000AE0000D70000D70000A60000E70000000000000000DF000000000000000000000000
+0000C20000C20000D20000BA0000BA00009E00218A00000000FFFF00FFFF00FFFF00FFFF00FFFF00
+FFFF00000000FFFF00FFFF00000000FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF0000000000DB0000CA0000CE00089A0000000000B60000DB0000BE0000D7000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF00000000000000000000000000000000
+0000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF000000
+000000000000000000000000000000000000000000000000000000000000D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CE000000D6D2CED6D2CE000000000000000000000000000000000000000000000000000000000000
+000000FFFFFFFFFFFF000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000
+00000000000000000000000000000000000000000000FFFFFFFFFFFF000000D6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000FFFFFFFF
+FFFF000000000000000000000000000000000000000000FFFFFFFFFFFF0000000000000000009492
+94949294D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+000000000000000000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000
+0000000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CE000000FFFFFFFFFFFF313131FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000000000000000000000009E00089A0031820000000000000000
+000000000000000000000000D2000000005265E65265E65265E65265E65265E65265E65265E65265
+E65265E6000000000000000000000000109200009E0000A60000A200000000000000000000089A00
+00BA0000CE0000A20000CE0000C6000000000000005265E60000000000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000000000000000E70000BE00
+00AA0000E3000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000000000000000000000000000000000000000AE
+00089A003A7D0000DB00198E0000C20000000000E30000BA004A75080000005265E65265E65265E6
+5265E6000000009E00318200298600089A00000000089A00109200089A00109200000000089A0042
+79000000000000005265E65265E65265E65265E65265E65265E600000000BA0000D70000B2003A7D
+00218E003A7D0010920000AA00000000009E0000CA00089A0000D70000BA0000AA00000000000000
+00000000000000BA00000000009E0000B60000CE0000A60000B60000C600109200000000FFFF00FF
+FF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00000000FFFF00FFFF00FFFF00000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF0000000000C60000C20000D20000B60000000000B20000B600
+00A20000B20000D7000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000
+000000949294D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000
+00000000000000000000000000000000949294D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000949294D6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000
+0000000000000000D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000000000000000000000FFFFFF000000000000000000000000000000FFFFFF000000000000
+000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF313131313131313131313131FF
+FFFFFFFFFF313131313131313131313131313131313131313131FFFFFFFFFFFF000000949294D6D2
+CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600
+0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000000000000000000000CE
+00109200298600000000000000000000000000009E00089A000000000000005265E65265E6000000
+0000000000000000005265E65265E65265E65265E600000000CE0000A20000CE0000000000000000
+A600089A00089600218A00089A00089A0000A20000B60000DB0000BE000000000000000000000000
+000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+E70000D20000A60000AE0000DF0000DB0000DB000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E600000000CE0000000000CA0000D700109200009E00
+00E30000000000000000C200009E00218A0042790008960029860000000000DB0000000052710800
+00005265E65265E65265E65265E600000000000031820019920000DB0000000000BE002986004A75
+08089A0000000000CA0042790000C6000000005265E65265E65265E65265E65265E6000000000000
+089A0000000000000000AA002986003A7D00109600089A0000000000B600089A0000D20000CA0008
+9A0000AE0000DF0000CA0000AE0000000000CA0000000000DB0000DB00009E0000B200009E0000B2
+00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00000000
+FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000B20000DF0000
+DB0000000000C60000DB0000B60000C2000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000949294
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000D6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFF000000949294D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE94929400000000000000000000000000000000000000000000
+0000000000000000000000949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294000000000000000000
+000000000000000000000000000000000000000000000000949294949294949294D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF3131
+31FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008
+96000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000AA00000000
+00000000000000000000000000DF00218A00089A0000A60000000029860000C20000AA0000000000
+00000000000000000000000000000000000000005265E65265E65265E60000000000000000000000
+0000000000C600009E0000AE00109200198E00218A0000BA0000C60000AA0000A20000B600000000
+0000000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E600000000D20000D20000AA0000DF0000DB0000BA0000AA000000000000005265E6
+5265E65265E65265E65265E65265E65265E65265E60000000000005265E600000000000000E70000
+C200089600089A0000AE0000E30000C20000000008960000A20008960029860031820000000000DF
+0000C2000000005271100000000000000000000000005265E65265E60000004A7508527508199200
+000000009E002986004A7508198E0000000000CA004279002986000000005265E65265E65265E652
+65E65265E600000000000000AE0000DF0000D700000000109200218A0000CA0000000000B200089A
+0000B60000C20000D20000C20000DB00009E0000B600009E0000000000AE0000CA0000000000CE00
+00A20000CE0000CE00089A00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000
+0000FFFF00FFFF00000000FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+0000000000AE0000D20000A20000000000D70000C60000B60000BA000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CE000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CE00000000000000000000000000000000000000000000000000
+0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2
+CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CE000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF
+FFFF000000949294949294D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE000000000000D6D2CE000000000000000000000000000000000000
+000000000000000000000000000000FFFFFFFFFFFF000000949294949294D6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE9492940000000000
+00000000000000000000000000000000949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE949294000000000000000000000000000000000000000000949294949294949294D6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+000000FFFFFFFFFFFF313131FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE0896000896000896000896000896000896000896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF0000000000000000000000CE0000CA0000000000000010960031820042790029860000D7001096
+002986000000000000000000000000000000005265E6000000009E000000000000005265E65265E6
+00000000000000E70000DF0000D70000C20000CE0000A60000BE0010920010960010920000BE0000
+A20000DB0000000000D70000DB000000000000000000000000005265E60000000000000000005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E600000000000000E70000B60000A60000D70000AE0000AE0000
+AE0000A6000000005265E65265E65265E65265E65265E65265E65265E65265E60000000000005265
+E600000000000000E30000B200109200198E0000B600089A00218A0000AE000000003A7D00109200
+218A0000000000DB00218A005275080000000000000000000000005265E60000005265E65265E600
+000000A6005A6D1029860000000000BA00298600427908198E0000000000A2002986004A750800A2
+0000000000000000000000000000000000000000000000DB0000DF0000B20000D700000000000000
+00000000000000000000D20000C60000C20000BE0000B60000AE0000D70000D70000D70000000000
+C20000000000B60000BA0000AA0000CE0000B60000C600089600000000FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00000000FFFF00FFFF0000000000000000000000BA00000000FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00000000089A0000AE00009E0000AA0000A20000000000B60000D70000C20000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CE000000000000000000000000000000000000000000D6D2CED6D2CE00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE949294949294949294949294949294949294949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294949294949294949294949294949294
+949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFF313131313131313131313131FFFFFFFFFFFF3131
+31313131313131313131313131313131313131FFFFFFFFFFFF000000949294D6D2CED6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+00FFFF00FFFF0000000000000008960000000029860010920000B200000000000000000000000000
+00D200298600427900198E0000BE0000000000000000000000000000000000000000000000BA0000
+AE000000005265E65265E65265E600000000CA0000B600000000089A00009E0000D20000CE0000A6
+00198E0000000000000000000000000000BE0000CE0000B60000000000C600089600000000000000
+00000000AA000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000D20000D20000BE
+0000CA0000BA0000D700009E0000D2000000000000005265E65265E65265E65265E65265E65265E6
+5265E65265E60000005265E65265E600000000AA0000BE0000BA0019920000AE0000D70031820000
+DB0000000000BA003A7D0029860000000000DB003A7D004279004A75080000000000005265E65265
+E60000000000005265E6000000000000089A00298600000000089600636D104A750800BA00000000
+00A60063691052750800A2003A7D00218A00218A0000E30000DF0000000000000000000000CA0000
+9E00009E0000A200000000000000FFFF00FFFF0000000000000000A20000AA0000B20000B60000C6
+0000B60000000000DB00089A0000000000000000BA0000A60000CE0000AA00009E0000A200000000
+FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF0000000000A600198E0000AE0000
+0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000089A0000BE0000BA0000CE0000BE0000B2
+0000000000D2000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000009492949492
+94D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFF
+FFD6D2CED6D2CED6D2CE000000000000000000000000000000D6D2CE000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000949294949294D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000
+00D6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+949294949294D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFF
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000094
+9294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896
+000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E60000000000005265E600000000000000000000AA0010960008960000
+00002986000000000000000896003A7D0031820000AE00000000000000089A000000000000000000
+0000000000000000BE0000DF000000000000000000005265E65265E600000000D20000C600000000
+000000000000000000000000000000109600009E0000DB0000CE0000A20000A20000DB0000A60010
+920000CA000000000000000000000000000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+00000000000000D20010920000CA0000D70000CE0000D70000B6000000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E600000000000000000000BA0000A60000B200298A
+00198E0000B6004A79083A7D00009E000000005A7110298600000000000000000000000000000000
+0000000000000000000000005265E60000005265E65265E600000000DB0000DB0000000000BA0063
+6D1042790000A20000000000CE005A6D105A711008960000A20000D200318E9C19BA4A00E3000000
+0000000000000000000019920000AE00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+00B60000D70000DB0000CA00089A0000000000D200089A0000B20000000000DB0000AE0000AA0008
+9A00009E00109600109600000000000000FFFF00FFFF00000000000000FFFF0000000000000000A6
+0010920000BA00009E00109200000000000000FFFF00FFFF0000000000000031820000AA0000CA00
+00DB0000CA0000C60000CE000000000000000000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CE000000000000000000000000000000000000000000000000000000000000
+000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000000000000000000000000000000000
+00000000000000000000000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CE00000000
+0000000000000000000000000000000000000000000000000000000000949294949294D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000D6D2CED6D2CE00000000000000000000000000000000000000000000000000
+0000000000000000949294949294D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE00000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600
+0896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000218E
+00218A0000B600298600000000109600109600009E0000B20000B20029860000D700000000000000
+009E0000000000000000000000000000A200089A0000CA0000CA000000000000000000005265E600
+000000000000B20000BE0000C60000BE0000A600109200009E00089A0000A20000CE00009E0000CA
+0000BE0000B20000CE000000000000000000000000000000000000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000C20008960000CA0000D20000C60000CA0000D20000AE
+000000000000005265E65265E65265E65265E65265E65265E65265E65265E600000000D700000000
+089600218A00218E0000A20031820000D20000DB00218A0000DB00000000198E003A7D0000000000
+A2006369103182003182000000000000000000000000000000000000000000005265E65265E60000
+000000000000001092007365194A790800B200000000009E00736519298600218A00000000000000
+318E9C00E30000000000BE0000000000E70000000000DF0000B200000000FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF0000000008960000A20000A20000BA0000CE0000D200000000009E0000A2000000
+0000DB0000AE0010960010920008960000A2000896003A7D00198E00000000000000089600000000
+00000000BE0010920000A60000A200009E00009E00109200218A0000B200000000000000089A0010
+920000AE00109200089A0000CE0000B60000C200009E000000000000000000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE94929494929494929494929494929494
+9294949294949294949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE949294
+949294949294949294949294949294949294949294949294949294949294D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CE949294949294949294949294949294949294949294949294949294949294
+949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE9492949492949492949492
+94949294949294949294949294949294949294949294D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2
+CED6D2CED6D2CE949294949294949294949294949294949294949294949294949294949294949294
+949294949294949294949294949294949294949294949294D6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896000896000896000896000896000896000896000896005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000
+5265E65265E600000000000000000000BE00199200000000009E00218A00427D002986003182003A
+7D0000A20000BE0000D70000000000000000000000000000000000A20000BA00089A0000C6000000
+00000000000000000000000000000000089A0000AA00009E0000CA0000A600109200089A00009E00
+00AE00009E0000A20010960000BE0008960010960000000000000000000000000000000000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000E70000CA0000AE0000C200
+00DB0000C20000C200009E000000000000005265E65265E65265E65265E60000000000005265E652
+65E600000000E300000000089600298600218A00218A0029860010960000A6004A79080896001992
+00000000000000218A003182006B69103A7D0052710800000000E70000C60000B20000CA00000000
+0000005265E600000000BA000000000000000000007365194A7908298A0000000000B2006369105A
+6D1000000000000000B60000000000E70000000000DF0000000000D70000000000BA00000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000AA0000CE0000A600009E0000CE00
+00000000000000D20000000000000000C60000A20000C60000CE0000C60000AA00218A0000000000
+A2003182001992002986003182004A7508218A0000A600009E0000BA00009E0000BA00218E001092
+0000A60000A60000BE00318200218A00009E0010920000DB0000C200009E00000000000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482
+84424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284
+424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600089600
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E60000000000000000000000005265E60000000000000000000000000000001992002986
+00218E00198E00089A003182003A7D002986003A7D00000000000000000000000000000000009E00
+00CE0000C60000000000000000000000000000000000000000000000CA0000DF0000BE0010960010
+960010920008960000BA0000AA0000B200009E0000A600198E00089A001096000000000000000000
+000000000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+BE0000C60010960000A20000CE0000D200009E0000B6000000000000000000005265E65265E65265
+E60000005265E65265E65265E65265E600000000DF0000D200109600089600427900318200427900
+3A7D00298600318200089A00089600089600218A007365196B6919636910218A0000000000E30000
+BE0000A6004A750800B6000000000000005265E60000000000000000000000000000004279004279
+0000000000A2003182000000003A7D0031820000B20000000000E70000000000E300000000000000
+00DB0000DF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000C60008
+9A0000A20000CE0000C60000000000CE0000000000AA00000000000000089A0000B20000B200089A
+0000A200109200000000089A00298600218A003A820031820029860000BA00089600218A0000AE00
+00BE00109600109600109200089A0000BA00198E00527108218E00198E00218E0000DB0000D20000
+E7000000000000005265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE84828442
+4142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE8482844241
+42FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008
+96000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6000000000000198E0000A2000000000000005265E6000000000000
+00000000000010960008960000BE0000AA0010960029860042790029860000CE0000000008960000
+000000000000D200218A00089A0000A20000000000000000000000000000000000000000000000E7
+0000D20000AE0008960000B200089A0010960000B200199200198E00009E0000AA0000BE00089A00
+00D20000000000000000A60000CE0000B20000A600198E000000000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E600000000DF0000AE0010920000AA0000B20000C200009E0000CE0000D200000000
+0000005265E65265E65265E65265E65265E65265E65265E65265E600000000000000DF0000D70000
+AE00089A004A7908318200636D1052710852710800AE004A7908427900636910427D005275081992
+0000000000CA0000D70019920010960029860000CE001092000000005265E65265E65265E6000000
+00000000CA0000000000000000B6000000000000005271087365194A750800BE0000000000E30008
+960000000000000000B60000000000AA0000C600000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+0000000010920010960000D200009E00009E00109200000000009E0000000000000000AA0000D200
+000000089A0000B20000CE000896000000000000000896003A7D003A7D00298600527508218A0010
+9200198E00009E00109200089A00089A00089A0000B20000BE0000BE00218A00218A001096001092
+00009E0000C60000C60000AE000000000000000000005265E65265E65265E65265E65265E6000000
+00000000D7001092000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142
+FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FF
+FFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142FFFFFFD6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+000896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E60000000000003A7D0010960000D20000
+0000000000000000000000000000000000000000000000198E0000A6003A7D005271085275083A7D
+0000CE0000B200218A00198E0000000000AE0010920000AE0000D200000000000000009E0000CA00
+00000000000000000000000000C20010920000AE00109200089A00089A00198E0010920010920000
+DB0000D20000A20019920000A20000000000A600298600089600109600009E00198E000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E600000000000000C200109200009E0000D70000DB0008
+9A0000AA0000DB0000C2000000000000000000000000005265E65265E65265E65265E65265E65265
+E600000000E30000B20000AA0000C200089A0000DB0000B600009E000896005275085A7110736519
+218E00218A003A7D0031820000000000DF0000C6003A7D0073651931820000B60052750800000000
+00005265E65265E600000000000042790000A60000000000000000C600427900527508427D003A7D
+0008960000000000E30000BE0000000000E30000000000000000CE0000CE00000000FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000109200089A0010960000D20010920010960000000000B20000
+A20000000000000000C600089A0000000000C60000B20000A60000AA00000000218E00218A004279
+00318200298600109600109200198E00198E00198E00109200198E0000BA00089A00109600198E00
+218A0010920010960000A60000D70000B60000C60000D2000000000000000000005265E65265E652
+65E600000000000000000000BE00198E00009E000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFF
+FF848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284424142FFFFFF8482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284424142FFFFFF84828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284424142FFFFFF
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284424142FFFFFF848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284848284848284848284848284424142FFFFFF8482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284848284848284848284848284848284848284848284848284848284424142FFFFFF84
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284D6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+0000AA004279004A750800000000AE0000000000000000000000000000000000000000000000BE00
+3A7D001092004A75084A7508298600318200198E0000CE0000B60000AA00089600089A0000000000
+000000000000B600009E0000000000000000000000000000AE0000AE0008960000B200198E001092
+00198E00198E00089A0000CE0000AA0000AE0000AE0000AA00000000089600009E00089A00109200
+00BE000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000C6002986
+0000C60000DB0000DB0000CA0000C60000CE0000B600089A000000000000000000005265E65265E6
+5265E65265E65265E65265E600000000000000BE0010920000C2002986004279005A711052711029
+860052711000AE0000CE0008960000000000000000000000E30000E7001092006369105271104279
+00009E00089A0000A2000000000000005265E65265E6000000089A0029860000A20000000000D200
+00D200089A0042790031820000CE0000D20000000000DF0000000000E30000000000000010920000
+9E0000BE00000000000000FFFF00FFFF0000000000000000A20010920000B20000B20000B2001092
+0000000000AE0010960000AE0000000000A20010960000C60000000000B20000C60000C60000A600
+000000089A001992004279087365192986003A8200109200298600109200089A00089A0010920010
+9200218A001096003182003A7D0010960010960000C200009E0000C60000C6000000000000000000
+005265E65265E600000000000000DB0000000000000000BE003A7D000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E60896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CE84828442414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+4142D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896
+000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E600000000000000000000000000B200009E0000AA0000000000000000B20000
+000000000000000000000000000000000000C200427900318200298600198E0010920000CE001092
+0000A20000A60000000000000000000000D20000000000000000000000E70000000000BA0000C600
+00CE0000A600109200109200218A00089A0010960000A60000D70000B60000AE0000000000B60000
+DB0000CE00198E001096000896000000000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E600000000000000BA0000C200089A0000AA0000AA0000A60000CE0000CE0000000000B2003A
+7D000000000000005265E65265E65265E65265E65265E65265E600000000D70008960000DB0000D2
+0000AA0000D2003A7D00636D1073651900000000000000000000A20031820000000000000000E300
+1992007B65194A75084A790800A6004A7508009E000000000000005265E65265E600000000B20019
+8E00089A00000000198E00109200527108218A0008960000C60000000000000000AE000000000000
+0000000000000000DB0000C20000AE0010920000000000000000000000CA0000C60000AA0000AA00
+00A20010920000CE0000B200000000089A0000B20000A20000000000AA0000CE00009E0000000000
+B20000B20000C60000BE00000000109600218A002986006B6910318200427900318200318200009E
+0000BA0010960000BA00089A00218A003182003A7D00218A0008960010920000DB0000CA0000A200
+00D70019BA4A000000000000000000000000000000109600009E0000BA00089A0000000000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600
+0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E60000005265E65265E65265E65265E65265E65265E6000000218A0000C200218E000000000000
+00089600000000109200218A00089A001092000000000000000000003182003A7D005A7110298600
+10960010920000B20000A60000D70000D70000000000000000A200009E0000000000000000000000
+BE0000000000AE0000A200009E00009E00009E00218A0008960010960019920010920000BE0000DF
+0000BE0000000000CE0000B20000BE0010920010960000AA00218A000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E600000000E70000B200089A0008960000AE0000CE0000D20000DB
+0000000000000000CA00089A003A7D000000005265E65265E65265E65265E65265E65265E6000000
+009E00427900318200199200009E003A7D003182003A7D000000004A75083A7D0052710800000000
+0000FFFF00FFFF00000000000000636D107365192986004279005275083182000000000000005265
+E65265E60000000000000000000000000000003A7D00198E0031820052711031820000C600000000
+00DF00089A0000000000000000D20000AA0000D70000000000000000D20000000000CE0000B20000
+9E00318200318200089A00089A0000B600089A0000B20000000000DB0000BA00000000009E0000C2
+0000B200089A00000000109600089600109600089A00000000109200218A00298A003A7D004A7508
+3A7D00089A00218A00218A00218A00089A00089600109200109600218A00109200089A0000A60000
+A60000C20000B20000C60000E30000000000000000000000000000A200089A0031820010960000B6
+0000B60029860000E3000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008
+9600089600089600089600089600089600089600089600089600089600089600089600089600D6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6
+D2CE0896000896000896000896000896000896000896000896005265E65265E65265E65265E65265
+E65265E65265E65265E60000000000000000000000005265E65265E65265E65265E6000000000000
+000000000000198E0000CE00089600198E00000000199200198E003A7D003A7D00218A003A7D0000
+A600198E00318200318200089600198E0008960000C60000AA00089A00000000000000009E000000
+0000000000000000B20000000000000000AA0000AA0000C200109600109600198E0010960000BE00
+009E00009E0000B60000C60000000000CE0000D20000B600009E0010960000A20000CA0000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000009E0000BA00000000
+00000000000000000000000000000000000000D2002986004279000000005265E65265E65265E652
+65E65265E65265E600000000000000BE003A7D005271083182002986004A75087B65190000005A71
+107B6D21000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000005A71107B651900A600527108
+089A000000000000000000005265E60000001092000896000000000000004A750842790031820010
+960019920000CE0000000000E30010960000E70000000000B600089A0000C2000000000000000000
+0000B20000A20000C20000BE00298600198E00089A0010960008960029860000A60000000000BA00
+00000000000000AE0000C20000A200089A00000000109600089A00009E0000000000B200009E0019
+8E00218A004A7908318200318200298600218A00198E00089A00198E00198E00089A0000A60000AA
+0000CA0000C60000CE0000AA0000DF0000B60000DB0000000000000000E30000000000B600427D00
+4A75084A750800A200009E004A7508009E0000DF00000000318E9C0000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442
+41428482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+8284848284848284848284848284848284848284848284848284848284848284FFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E600000000000000AE000000000000005265E652
+65E65265E65265E600000000000000000000000000CA0031820000000000B2003A7D002986001092
+0000000000000000000000BE000896003182003A7D0010960029860000BA0000C600089A0000CA00
+00000000A60000000000000000000000000000CA0000000000000000000000A60000BE0010920010
+920008960000A60000A60000AA0000CE0000DB0000AA0000000000B20000D20000D20000A20000DB
+0000A20000D7000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+000000000000000000000000DB00009E00000000000000FFFF00FFFF000000000000004279000000
+000000005265E65265E65265E65265E65265E600000000000000D20000A2003A7D00198E00427900
+298600089A000000007B6519427900000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000073
+6519427900198E006B691010920000000000E30000000000000000000000AE0000BA000000000000
+00198E004A75085275083A7D0029860000BA0000000000CE0000C20000B60000000000C20000B600
+00C20000000000DB0000A20000B60000AA0000CE0000C600089A00089A00109600198E0029860031
+8200218A0000000000000000000000A60000A20000AA0000BA0000B200000000089A0010960000C2
+0000000000AE00009E00199200000000000000000000000000000000000000000000218E00218A00
+109600009E0000000000000000B20000C20000DF00089A0000000000000000000000000000E30000
+000000C20000C6004A75084A75083A7D0000BE00009E0042790000A60000000019BA4A00E300318E
+9C0000000000000000005265E65265E65265E65265E65265E60000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CE848284424142848284424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008
+96000896005265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+00009E00198E000000000000005265E65265E65265E65265E65265E6000000000000000000000000
+000000000000000000000000000000000000000000089A00198E003A820042790842790029860008
+9600089A0000CE0000DB0000A20000000000000000BA00009E00000000009E0000D7000000000000
+0000C600009E00089600089600009E00009E0000A20000BE0010920000D20008960000000000B200
+089A0000E3000000000000000000000000000000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E6000000000000009E0010920000CE0000BE00000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF000000000000000000005265E65265E65265E65265E600000000000000000000000000
+000000000000C20000000000000000000000B20000C600000000FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF000000007B651900B2005A6D1000B60000000000DF000000005265E6000000
+00A60010920000000000000000D7001092003A7D004A7508218A0000BA0000000000DB0000CA0000
+000000000000CE0000BA0000D20000000000DB00009E0000BA00009E0000CE00109200218A00089A
+00089A00198E00298600198E00198E0000000000CE0000000000AE0000BA0000CE0000BA0000B200
+00000000B200009E0000000000A200089A001092000000000000002986003A7D0031820029860021
+8E00218A00000000000000000000000000FFFF00FFFF0000000000000000000000000000C2000000
+0000000000000000000000C20000B600298A00527110427900009E0008960052710829860000E700
+00000019BA4A00E300318E9C000000318E9C00D2000000000000005265E65265E65265E600000000
+00005265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896
+000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6000000000000089A000000000000000000000000000000005265E65265E65265E652
+65E600000000000000000000000000000000000000000000000000000000DB0000B2001992002986
+0031820029860029860019920000BA0008960000D20000BA0000AE0000000000BE0000B600000000
+00C60000B20000000000000000000000000000A20000A600009E00009E00089A0000B60000000000
+000000000000000000000000B60000BA000000000000000000000000005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E6000000089A00009E0000AE00000000000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00000000089A000000005265E60000000000005265E60000
+0000000000A600000000000000000000000000089A00089A00089A00198E0000AA00000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000003A7D00009E0000B20000000000000000
+000000000000000000000000000000000000000000000000000000000000C60000A600198E001096
+0000000000BA0000000000000000B60000000000CE0000DB00009E0000000000DF0000B60000A200
+109600109200009E00089A00009E00089A00298600218A0000000008960000000010960000AA0000
+DB0000AA0000A20000A60000BA00000000000000000000000000089A00000000218E00198E003182
+00427D003A7D003182003A7D00318200109600000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+00000000000000000000DB0000000000000000000000D2000896004A75087B65196B69192986004A
+7508527108089A0000AA0000000000E30019BA4A000000000000318E9C00E30000D7005265E60000
+0000000000000000C20000AE000000005265E65265E65265E65265E65265E65265E65265E6089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482844241
+42FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CED6D2CE0896000896000896000896000896000896000896005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E6000000000000000000000000089A0000DB0000DF000000
+000000005265E65265E65265E65265E6000000000000000000000000000000000000000000000000
+00AA0000B200218A00298600218A003A7D00218A003A7D00198E00198E0000AE0000A60000000019
+8E0010960000000000CE0008960000C60000A20000B20000000000BE000000000000000000000000
+0000000000000000BA0000000000BA0000000000000000D70000CE0000D20000C200000000000000
+0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000BA0000D2
+00000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000000000
+00000000000000000000000000000000CA00009E00089A0000BA00000000000000427D004279003A
+82003A7D00109200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000006B69103A7D0000A6
+0000E300000000009E0000000000000000000000000000A200198E00000000089A00009E0000C600
+00000000000000000000000000E70000B60000000000CA0000AA0000000000A20000D70000DB0000
+000000000000DB0000BE00109600109600089A0000BE00218E0000AA00218A0010960000000000A6
+0000000000C60000B20000DF0000AA0000BA0000A20000A20000B200000000000000000000000000
+109200109600198E001092003182003A7D00298600298600218E00318200000000FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00000000009E0000000000000000000000000000000000AE00198E005A71
+107B69215A71103182004A75084A750800DB0000000000000000E70000E300000000318E9C000000
+00000000E30000E300318E9C0000000000000000000000000000000000005265E65265E65265E652
+65E65265E65265E60896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000BA00000000
+00B20029860000C60000C6000000000000000000005265E600000000000000DB0000BA0000C60000
+D70000AA00009E0000000000A20000BE00089600218A00218A00199200218A00109200089600218E
+00109600109600000000198E00198E0000000000D20000A600009E0000C600109200000000089600
+00B20000C60000D70000AE0000CA0000000010920000000000000000000000000000000000C60000
+B20000DB0000AE000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E6000000000000000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00000000000000318E9C318E9C00CA0000000000000000E70000CA003A8200198E001092002986
+000000002986007365196369107B69194A7508000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+0000004A7508218A0000A60000000000CE0000AA0000DB0000000000000000000000000031820019
+920000000000000029860010920000A60000000000000000000000000000000000AA0000B6000000
+0000D20000CA0000B200009E0000CE0000000000000000AA0000C60000C60008960000A60000CE00
+089A00000000009E0000C60000000000000000000000000000000000DB0000A20000DB0000DF0000
+0000000000000000089600218E00198E004279001096004279004279002986004A7508218A000000
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000BA0000C200000000
+000000009E001992002986007365195271103A7D004A750831820000BA0000000000000000DF0000
+000000E30000E300318E9C000000000000000000000000009E0000CA0000DF000000000000000000
+005265E60000000000005265E65265E65265E65265E6089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600
+0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E600000000000000AE00000000218A00198E00089600009E0000AA000000000000005265E60000
+00000000000000198E0000A600000000000000000000089600198E00218E00109600009E00109200
+00BA00109200109200198E0010920000000000C200109600109200000000089600218A0010920021
+8A00109200000000009E00009E0000A60000A20000C60000000000AA0000A20000B20000B6000000
+0000000000000000000000C20000BA0000DB000000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E600000000000000D70000C600000000000000FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF00000000089A0000D700000000318E9C00DF0000DF0000000000DF0000C600
+009E005A6D10427D0000000000000000CE00089A007B69197B71214A7508636910000000000000FF
+FF00FFFF0000000000000010960000A60000AE0000000000D700089A0031820000A60010960000E7
+00000000000000218E0010960000BE00000000298600218A004A7908298600089A00000000000000
+00DB0000A20000CE0000000000000000D70000D70000BA00009E0000AE00009E0000000000000000
+000000A60000000000000000000000000000000000000000AE0000B20000B20000B60000A2000000
+00000000000000000000009E0000000000C60000A600218A00427900218A002986003182003A7D00
+298600318200198E00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000
+0000089A0000AE0000000000BE000000004279004279007B65195A6D10527108009E0010960000AE
+0000000000E30000DF00000000318E9C00DF00318E9C318E9C318E9C00DF0000CA0000A20000DB00
+00D200009E0000C2000000000000000000000000005265E65265E65265E65265E608960008960008
+9600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08
+96000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E600000000000000DB0000D20000B600009E00109600000000
+0000000000005265E65265E6000000000000000000000000000000000000089A00009E00218A0000
+9E00198E00109200218A0000B60000CA0000C60000AE0000A60000000000CE0000BE000000000000
+00218A002986003A7D00318200089A0000A20000000000AE0000A600009E0000000000A200109200
+00BE00009E0000C6000000000000005265E60000000000000000000000005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+000000005265E65265E65265E65265E65265E65265E600000000000000000000DB00089A00009E00
+000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000298600089600000000318E9C00E30000
+DF0000E30000000000B6004A7508298A004279005A711000000000BA005A6D103182007365197B6D
+217365197B65197365190000000000005A711000BE0000C600000000000000000000198E004A7508
+636D10009E0000C20000A60000000000000000BE0031820000C60000C60000000042790052750831
+8200218A0000CE0000000000000000DF0000B60000D70000AE0000000000D200089A00009E0000DB
+0000B20000000000DB0000DB0000000000000000A20000B60000A60000B20000AE0000AE0000AE00
+00CE0000A20000A20000AE0000AE0000000000C60000AA0000D200000000089A0019920042790008
+9A003A7D004279003182004A75083A7D00198E00198E00000000FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF0000000000000000D700009E00089A0000BE00109200000000427908527110736519527110
+318200089A0000DB00089A0000000000DF0000CA0000000000DF0000E30000E30000DF0000E70000
+D20000D20008960000C60000A200218A0000AE0000000000000000C2000000000000000000005265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284
+8284424142FFFFFFFFFFFFFFFFFFFFFFFF848284848284848284848284848284848284848284FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896005265E65265E65265E6
+5265E65265E60000000000005265E65265E65265E600000000000000000000000000000000000000
+C60000000000000000B20000D700089A000000005265E65265E6000000000000000000089A000000
+0010920000B20000CA0000A200009E00089A0010960010920000C60000DB0000B200009E00000000
+00BE0000B600000000218E0000B600218A004A75083A7D0000AE0000BA0000A200000000089A0000
+9E00000000109200089A0000B2000000000000000000000000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E60000000000000000005265E65265E65265E65265E65265E65265E65265E600000000
+000000D700109200089A0000D700000000000000FFFF00FFFF0000000000000000D20000BA004279
+0000000000E30000E30000E30000E70000000000C2003A7D005271087B691952750800000000A200
+5271087B69197B71217365197B69197B6519636D105A6D10089A00009E0010920000000000C60000
+000000BE004A75087B75217B6D2100BE0000C60000DB0000000000000000C200218A0000C20000C6
+000000004A79085275083A7D003A7D0000AA00000000000000089A0000DB0000A20000AA00000000
+000000009E00009E0000DF0000000000000000B20000000000DB0000A20000DF0000B60000A60000
+AE0000B20000CE0000AE0000A60000AE0000DF0000AA0000A60000000010960000CE0000CE000000
+0000B200109600198E00218A003A7D00198E00318200218A004279003A7D00109200000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF0000000000CA0010960000A20000CE00109200089A000000004A
+75084A75085A6D10527108298600089A0000DB0000D70000000000CA0000BE0000000000DF0000DF
+0019BA4A00E30000E30000D70000AE0000A60000A6004A750800CE0000A60000000000DB00000000
+00000000C6000000005265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFF000000000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFF000000000000FFFFFFFFFFFF000000000000000000FFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000
+FFFFFFFFFFFF000000FFFFFF000000000000FFFFFFFFFFFFFFFFFF000000000000000000000000FF
+FFFF000000000000000000FFFFFF000000000000FFFFFFFFFFFFFFFFFF000000000000000000FFFF
+FFFFFFFF000000000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008
+96005265E65265E65265E65265E60000000000000000000000005265E65265E600000000C20000BA
+0000000000000000000000000000B60000D200218A00089600000000000000000000000000000000
+00000000D70000000000000010960000C60000C600198E0000A20000000000000000000000000000
+CE0000B200089A0000000000000000000000AA0010920000A200198E003A7D0010920000C60000AA
+0000A60000D700000000000000089A0000BE0000000000000000CE0000D700000000000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E600000000000000CA000000005265E65265E65265E65265E65265
+E65265E600000000000000000000000000000042790000A600000000089600000000000000000000
+198E0000BA003A7D0010960000C60000000000000019BA4A00000000E30000CA0000000000000073
+65195275085A7110000000000000318200636910636D107B75217365197B71216B69104A75083182
+0000000000D70000B6000000003182006B691063691073651900B200089A0000BE00000000000000
+00A600318200427D00089A00000000000000427900427D004A750810920000A60000000010920000
+A20000A20000DB0000DB0000000000000000BE0000000000DF0000DF0000DB00000000009E0000B6
+0000A60000BA0000A20000AE0000B20010920000A20000B200089A0000AE0000AE0000CE00000000
+10960010960000D20000C60000000000BA00218E003A7D00218A00318200298600298A0042790021
+8A00199200318200000000000000FFFF00FFFF0000000000000000A600009E00009E0000BA00009E
+00109200298A002986000000004279005A7110427908089600218A0000C60000000000DF0000CA00
+00BA0000000000000000000000000000000000BA0000D70000CE003A7D0000A6003A7D0010960000
+C200000000218E0010960000000000C6000000005265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF84
+8284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFF000000FFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000000000FFFFFFFFFFFF000000FFFFFF000000FFFF
+FFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896
+000896000896000896000896005265E65265E65265E600000000000000AA0000D200000000000000
+5265E60000005265E600D20000D200000000000000000000009E0000B200089A0000C60000000000
+000000000000000000000000000000BA00198E0010960000000000CE0000B60000C6000000000000
+0000000000000000000000000000000000000000000000000000000000000000BE00198E00109600
+218A00009E0010920000DB0000BE0000AE00000000009E00009E00198E0000000010960000A20000
+DB000000000000000000000000000000000000000000000000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000CA0000D7000000005265E6
+5265E65265E65265E65265E65265E600000000000000000000E70000000029860000BE0000000000
+0000318200000000000000089600198E003A7D00198E0000B20000BE00000000318E9C0000000000
+00000000FFFF00FFFF000000000000007365191092007369190000006369107B6D217B7121527110
+4A750831820042790000000000D70000B2000000006B69195275086B69195A6D101096003A7D0029
+860000A20000000000000000BE00199200318200298600198E0000D7000000005271083A7D002986
+00009E00000000000000009E00009E0000A20000A60000DB0000CE0000000000000000DF0000DF00
+00DF00000000009E0000AA0000B20000DB0000AE0000AE00009E0000AA0010920000C20010920000
+CA0000AE0000CE00009E0000000000AE0000C600009E00000000000000218E00218A00089600218A
+003182001992003A7D00109600089600089A003A7D0000000000000000000000BE0000A60000A600
+00A20000A20000AE00198E001992002986002986000000003182004A7908318200298A0029860000
+CA0000000000DF0000CA0000C20000E70000BE0000E70000DF0000000000DB000000000000000000
+000000000000000000000000000000001092000000000000000000005265E65265E65265E6089600
+089600089600089600089600089600089600089600089600089600089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFF
+FFFFFFFFFFFFFFFFFFFF848284000000000000000000000000000000848284FFFFFF848284FFFFFF
+848284FFFFFF848284FFFFFF848284FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000
+FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFFFFFFFF
+000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFF
+FFFF000000FFFFFFFFFFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFF0000000000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE0896000896000896000896000896000896000896005265E65265E65265E600000000000000
+B200089A0000BE000000000000005265E600000000000000000000CE0000000000000000000000B2
+0000D20000B200000000000000009E0019920000000000AE0000D20010920000CE0000000000B200
+00E30000000000A20000000000000000000000000000000000000000000000000000000000000000
+000000D20019920000BA00009E0000A20000C200109600089A0000000000000008960000A6000000
+0008960008960000B20000000000000000A20000B60000B60000BA0000CE0000AA000000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000010960000000000
+D700089A000000005265E65265E65265E65265E65265E65265E600000000CA0000E3000000000000
+00000000218A003182000000000000000000003A7D001992004A7508198E003A7D0000CA0000BE00
+000000318E9C000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000636D1063691029860000
+00000000000000006B69107B6D215A6D104A75080000003A7D000000000000007365197B69217369
+197B6519218A00527108218A00009E0000000000000000DB0000DB00298600298600218A0000D700
+0000003A7D004A7508298600009E0000000000000000A60000B60000AE0000C20000AE0000AA0000
+000000BE0000000000000000000000000000B20000A20000AA00089A0000A600109200298A00089A
+0000BE0000C20000BE00009E0000BE0000AA0000C60000B200000000109600198E00218A00000000
+009E00427908218A00218E00218A00218A002986004A7908298A00000000000000000000198E0000
+A20000BA0000BA0000B200109200298600198E00218A00198E00298600298600298A000000000000
+0000000029860010920000CE0000000000CA00089A0000E30000CA0000E70000CE0000E700000000
+000000000000198E005A6D10198E0000DF0000D70008960000000000000000AA00089A0000000000
+00005265E65265E60896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84
+8284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF00
+0000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFF
+FFFFFFFF000000FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000
+FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896005265E65265
+E65265E600000000000000000000000000000000BA00000000000000000000000000000000000000
+00BE0000000000C20000000000000000D20000AE00009E00000000089A0000D200000000218A0010
+960000A60000000000000000000000AE0000B2000000000000000000005265E60000000000000000
+0000000000000000000000000000A60000C20000A20000A60000A60000CE0000C200000000000000
+00000000DB0000000000BE00218E0000AE0000000000000000C600218A00089A0000B60000DF0000
+C2000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E60000
+00009E0000AE00000000009E0000DB00000000000000000000000000000000000000000000000000
+00E70000BA0000000010920000000000B6003A7D00089A0000A60000B200318200009E0029860008
+9A004A7908089A0000AA0000000000E300000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000
+007B6919736519527108736519736519000000527108109200218A00000000000000198E00000000
+0000004A75087B71217B71215A6D105A71107B7521089A000000000000000000003A7D0000CE0019
+8E003A7D00298600198E0000C6000000003A7D0000000000000000000000000000A20000AE0000A2
+0000A20000CE0000000000000000DB0010920000DB0000000000000000BE0000D20000C600009E00
+00B200109600109200009E0000AA0000AA0010960010960000C20010960000B20000C60000000000
+B2003182001096000000000896004A7908089A00199200318200318200427900736519000000009E
+0000BA0000A60000C20010920010920019920000BA00218A002986003A7D003A7D00218A00298600
+2986003182003A7D0029860029860000000000000000000000000000CA0000D70000DB0000CA0000
+CA0000E70000BE0000000000AA0000AA00218E00218A00198E0000A600198E0000BA0000C60000BE
+0000000010960000D7000000005265E65265E6089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFFFFFFFF000000000000FFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFF
+FFFFFF000000000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF
+000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600
+0896000896005265E600000000000000000000000000D70000A20000AA0000A20000D70000B20000
+000000DF0000000000000000000000000000A20000BA00089A000000001092001096000000000000
+0000AA0000000000BA00009E0000D70000000000000008960000CE000000000000000000005265E6
+00000000D70000000000000000000000000000000000000000000000DF0000B60000BE0000000000
+A20000000000000000D70000CE0000D20000000008960000C20000000000A20000000000B20000DB
+00089A0000A20000CE0000000000000000000000B6000000005265E65265E65265E65265E65265E6
+5265E65265E600000000BA00009E0000B60000000000BE0000000000000000000000000000000000
+000000000000000000000000B60000B60000AE00000000089A00000000000000218E0031820000AE
+0000A200199200198E00109600318200218A0000B20000DF00000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF000000007369196369100000000000007B6D2100000000000000000000
+00004279002986000000000000005271087365197B69216B69107B7921736519198E000000000000
+000896004279003A7D00009E004279004A790842790000C600000000000000FFFF00FFFF00000000
+00000000DB0000000000000000000000000000C60000B20000A200089A00109200109200009E0008
+9A0000A200109200089A00199200218E00218E00198E00199200089A0000A60010920000A60000A2
+0000C60000BE0000000000D2003182001092003A7D00000000000000218E00199200089A00318200
+2986004A7508000000218A00089A0000AA00089A0000A600109200089600198E00198E003A820042
+7900218A00298600298A00298600298600298600298600089A00089A0000DB0000C20000000000DB
+0000C20000D20000C20000E30000DF0000000008960000A60000AE0000B200089A0000A2004A7508
+198E003A7D00198E00198E0000B6000000000000005265E65265E65265E608960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFF
+FFFFFF848284848284848284848284848284848284848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000
+000000000000FFFFFFFFFFFFFFFFFF000000000000FFFFFF000000FFFFFF000000FFFFFFFFFFFF00
+0000FFFFFFFFFFFF000000000000FFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF0000000000
+00000000000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000
+FFFFFFFFFFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFF
+FFFFFFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008
+960008960008960008960008960008960000000000000000000000DB0000B60000CE0000AA000000
+00000000000000000000000000009E0000000000000000000000000000000000CE00109600089A00
+000000009E0000AE0000D20000000000A2000000000000000000005265E600000000000000000000
+00005265E65265E600000000000000C6000000000000000000000000000000000000000000000000
+0000000000000000000000BA0000000000000000000000D70000000000D700009E00000000009E00
+00000000A20000A60000CE0000CA0000AA0000000000000000000000D70000C2000000005265E652
+65E65265E65265E65265E65265E65265E600000000D70031820000C200000000089A000000000000
+0000000000000000000000000000000000000000000000AE00009E0000CA0000000000000000DB00
+00CE0000000000000031820000AA0000AA00109600089A0000A20000A60000A600009E00000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000000000FFFF00FFFF000000
+00000000089A005A71107B65194279081992000000000000007365197B69197B7521636910636910
+5A6D1000DB0000000000000000CA00009E006B691031820000AA00427908089A00000000FFFF00FF
+FF00FFFF00FFFF00FFFF00FFFF0000000000000000AE00089A0000AA0000B20000D200009E0000DB
+0000DB00089A0000DB0000DB0000B200089A003A82003A7D00218A003A7D00218A00198E00218A00
+089A00009E0010960000A60000BE0000C200000000109600089A0000BE00198E0000000029860008
+9A00218A00198E00298600000000000000218A0000B600009E0000A600009E0000A600109600198E
+00218A003A7D003A7D005A7110298600298600298600298600298A003A7D0010960000A60000B200
+00B60000000000AE0000000000CE0000BE0000C60000DF0000DF0000000000CA0000BE001092004A
+75084279003A7D0052750829860000AA00009E0008960000AE000000000000005265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284828442
+4142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE08960008960008960008960008960008960000000000CA0000CE0000B200000000
+000000000000000000000000009E0000CE0000BE0000000000000000000000000000000000000000
+000000000008960000AE00009E0000000000000000000000000000000000000000CA000000000000
+005265E65265E60000005265E65265E65265E6000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000010920000B20000000000BE00089A00089A0000C60000000000C60000000000B60000D7
+0000CA000000005265E65265E65265E65265E65265E65265E65265E600000000A20019920000A200
+00000010960000000000000000000000000000000000000000000000000000000000000000000000
+000000CA0000CA0000000000C20000D200000000000000218A00009E0000AA001092000896001096
+0000A600000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF000000003A7D007B6D217365190000000000007B691900000000
+00005275086B691952710829860000000000000000000000D2003182007365194A7508198E002986
+003A7D00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000B200009E0000B20000A200
+00B20000A60000DB0000CE00009E0000D70000AA0000D20000C6003182003A7D004279002986003A
+7D00298600218A0010960010920010920000BA0000AA0000B20000C60000000000C20000AE0000AE
+0000A600009E0000000000AE001092000000000000001096003A7D00198E00109600089A0000A200
+08960000B600089A00218A00198E003182004A7508427908318200298600298600298600218A0021
+8A00218A00009E0000CE0000C60000000010960000000000000000C20000D20000E30000DF000000
+0000DB00009E00198E002986004A7908218A0000AA00009E0000C600089A00000000000000000000
+0000005265E65265E65265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960000000000
+00000000000000000000000000000000005265E600000000000000000000000000A60000000000BA
+0000B20000D20000000000000000000000000000AE00198E0000D20000BE00000000000000000000
+009E0000AA000000000000005265E65265E65265E65265E65265E65265E60000005265E600000000
+00000000000000005265E65265E60000000000000000005265E60000000000000000000000000000
+00000000000000000000000000198E00089A00000000009E00009E00218A0000A600009E00000000
+009E0000000000D70000B6000000000000005265E65265E65265E65265E65265E65265E600000000
+000000B200199200089A0000A60000000000B6000000000000000000005265E60000000000000000
+00000000218A0000C20008960000000000000000C20000000000000000D700000000000000000000
+08960010960000000000000000000000B200089A00000000FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000007B6D21636D10000000218A
+00000000000000FFFF00FFFF00000000000000000000000000000000000000089A0000AE007B6519
+6B69195271083182004A7508000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000
+000000B20000CA0000B60000AA0000AE0000B20000AE00009E0000DB0000A2000896003182002986
+00218A00218A003A7D003A7D00298600318200089600198E0008960010920010960000B20000A600
+00000000AE00089A0010960000B20000B20000000000A6000000003182003A7D00198E0031820021
+8A00298600218A0010920000A200089A0000B600089A00198E002986004A7508427D00298600218A
+00198E00089A00198E00198E0000B200089A0000D200000000089A0000AA00009E0000000000CA00
+00DF0000DF0000DF0000000000D70000A200089A003A7D003A7D0073651900C20000B60000E30000
+00000000000000000000005265E65265E65265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896
+000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+000000000000000000089A0000000000000000000000DB0000D70000000000AE0000000000000000
+00000000000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E60000000000005265E65265E65265E65265E60000000000005265E6000000000000
+000000009E0000C200000000000000000000000000000000009E0000000000000000A600198E0010
+960000B20000000000A60000A200009E0000000000DB000000000000005265E65265E65265E65265
+E65265E65265E600000000000000DB0000BE00427900009E00000000000000000000000000000000
+5265E60000000000000000000000003A7D0000DB00218A003A7D0000BE0000000000D200009E0000
+0000000000000000109600000000000000009E0000CA0000AE0000AE0000AA000000000000000000
+00FFFF00FFFF00000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+00000000000000A600000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000000000
+00003A7D0000AE007B6D216B69195A6D104279004A7508000000FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF0000000000C60000BE0000B200009E0000B20000B20000CE0000CE0000CE00
+00D2001092006B6910427900298600427900318200318200318200218A00089A00218A00198E0019
+920000A60000A20000A20000000000AA00218E0010960000A20000C6001092000000000000002986
+000896003A8200427D00218A00198E00218E0000B600089600199200109200218A00218A00089A00
+3A7D00199200198E00199200089A00218A00198E0000B20000B20000000000000000000000AE0000
+A60000CE0000000000D20000BE0000DF0000000000BA00009E001096003A7D00298600089A0000A2
+0000AA0000E3001992000896000000000000000000005265E65265E65265E65265E65265E6089600
+089600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+0896000896000896000896000896000896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E600000000000000000000D20000AA0010960000B20000CE000000
+000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E652
+65E65265E6000000009E0000CA0008960000B20000000000000000000000000000000000000000C2
+0000DF0010920000AA0000BE0000000000A60000A20000C60000B200000000000000000000000000
+5265E65265E65265E65265E65265E65265E600000000AE0000B60000AE0042790031820000000000
+000000DF0000000000000000000000000000000000DF0000000008960000A2004A7508427D0000C6
+00000000089A00009E0000CE0000000000000000A20000CA00089600009E0000CE00298600298600
+00AE0000DB0000000000BE0000000000000000BA00636D10000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00000000000000318200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+0000000000B6000000000000003A7D0000C2007365197B69215275087365195A7110318200000000
+FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000B60000000000AA0000AA0000AA0000AA0000
+9E0000C60000BE00089A0000B200009E007365195A6D10218A00218A004279084279003182003182
+00198E00218A00218A0010920000A60000B20000C60000000000BE0000A20000A60008960000C600
+089600000000000000198E001992002986003182003A7D00198E00109600009E00218A00009E0019
+8E00089A00009E00089600198E00199200198E00198E0019920008960000B60000000000000000B2
+0000CE0000AA0010920000BE0000A600009E0000000000DB0000DF0000000000C200089A00109200
+31820052710831820008960000AE003A7D0029860000000000000000D2000000005265E65265E652
+65E65265E65265E60896000896000896000896000896000896000896000896000896000896000896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000D200009E00009E00
+089A0000B2000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+000000005265E65265E65265E65265E60000000000000000000000000000000000005265E6000000
+00000000000000000000C60000BE0000C20000000000000000000000000000000000000000000000
+00000000000000000000000000005265E65265E65265E65265E65265E6000000009E0000CE0000B2
+004A7508427D0000B60000000000E30000DB0000E30000000000BA0000A60000000000000000AA00
+089A0031820042790031820000CA0000000010960000DB0000CA0000000000A60000AE0000B20000
+A200009E00198E00298600218A0000BE0000000000CA0000D700000000009E004279004A75080000
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000427900636910000000FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000000000FFFF00FFFF000000000000006369106B691973651963
+6D107369195A6D10000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000AA000000000000
+0000000000B20000B20000AE0000D2003A7D00089A0000A600218A003A7D003A7D00218A00298600
+2986003182004A7908318200298600199200218A00109200009E00218A0000A60000A20000000000
+A600089A0010920010960000C20000000000A60000BA00318200198E00318200318200198E001092
+0000BE00109600198E00198E003A7D00198E00218A00218A00218E00109600109600000000000000
+00000000D20000D20000A600089A00218A0000BA0010920000A60000DB0000000000BE0000DF0000
+000000AA0000A6001992002986003A7D005271086369105A71104279080000000000000000000000
+005265E60000000000000000005265E65265E6089600089600089600089600089600089600089600
+089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000000D70010920000B20000CE0000DF000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E60000000000005265E65265E65265E65265E65265E65265E65265E600000019BA4A00
+00005265E65265E65265E65265E60000000000000000000000000000000000000000000000000896
+0000D70000B200000000000000000000009E0000D7000000005265E65265E65265E6000000000000
+00000000D20000D2001992003A7D00089A0000B60000000000DF0000000000000000C20000C20000
+CA000896000000000000004A750800AE00427D004A750800C60000000000C60000B20000B2000000
+0000000000BE0000BE0000B200009E00218A0042790829860010960000B60000000000BE0000D700
+000000000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000005A6D10636D1000
+0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00000000736519736519736519736519527108089A00000000000000FFFF00FFFF00000000000000
+3A7D0000A20000C60000000000A60010960010960000A60000D20029860010960000B200009E0021
+8E00298600198E003182003182005A71105A71103182003182004A7508218A00089A00109200089A
+0000A20000A60000000000000000B20008960000A60000A60000A2000000000000000000003A7D00
+4A7508298600089A00198E0000BA00218A00089600218E00198E00089A00218A00298A00198E0000
+9E0000000000AE00089A0000B200009E00218A00218A00218A00089A00109200218A0000AA0000D7
+0000000000E70000E30000000000CE00218A00109600009E00318200218A0010920000A600000000
+0000000000000000000000000000000000003A7D000000000000005265E608960008960008960008
+9600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008
+96000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E60000000000000000000000000000000000000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E652
+65E65265E65265E65265E60000000000000000005265E65265E65265E65265E65265E65265E65265
+E65265E60000000000000000005265E65265E65265E65265E60000005265E65265E6000000000000
+00000000000000000000A20000CE0000000000000000000000AA00009E0000E700089A0000000052
+65E65265E600000000000000000000000000000000000000000000000000000000000000E3000000
+0000D200109600198E0000D70000C200000000000000198E003A820000A6003A7D0000BA00000000
+00B600009E00009E0000000000000000CE0000B20000AA00218A00109200198E004A7508198E0000
+000000000000BE0000DB0000B60000BE0000000000B200000000000000FFFF00FFFF000000000000
+004279006369105A6D104A7508000000FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000636D107365197365197365193A7D00427900318200636D1000
+00000000001092003A7D0000000000000000000000000000CE0000AA0000C60000B200009E0000A6
+0000B20000B200009E00198E00218E00218A00199200318200527508427D004A7508298600199200
+198E00298600218A0000B60019920000A20010920000AE0000000000A60000A60000A60000B20000
+9E00089A002986000000000000003A7D00218A00109600109200199200198E00218A00009E001092
+00199200218A0000000000000010960008960000A600109200218A00218E00089A00198E003A7D00
+218A00218E0000CA0000AA0000BE0000000000000000000000D700198E00198E00089A00218A0008
+9A0029860000000000000000000000B2003A7D0000CA0000C2000000000000000000000000005265
+E6089600089600089600089600089600089600089600089600089600089600089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+000000000000000000000000000000FFFFFFFFFFFF000000000000000000000000000000FFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE0896000896000896000896000896000896005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E60000000000000000000000005265E65265E65265E65265E65265E60000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+000000000000000000000000000000DB0010920000000000000000000000A600009E0000B20000CA
+0000E30000DF000000005265E65265E600000000000000000000000000C200089A00198E0000A600
+00BA0000000000000000000000CA0000B6005A711000D70000AE0000000000E30000000031820019
+8E00089A00199200000000009E0010960000CE00000000000000009E0000A20000C60000CA0000A6
+00089A00298600218E00000000198E0000000000000000BE0000DB0000000000AA0000CE0000AE00
+0000000000004A79085A7110527108736519636910736519000000FFFF00FFFF00FFFF00FFFF0000
+0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000006B69197365197365193A7D
+00527508636910636D10427908318200000000000000FFFF00FFFF0000000000000000CE00009E00
+08960000B200089A0000A20000C60000B200109200109600109600109600109600198E004A750842
+7900298A002986003182003182004A7508199200218A00089A00009E00089600089A000000001092
+0000B20010960010920000BA00109600427D00218E003182000000003A7D00218A00009E00199200
+218A0000000000000000000000BA00000000089A0010960000BA00089A00089A00218A003A7D0019
+8E00298600298600109600218E00089A0000B60000CA0000AA000000000000000000000000000000
+00000000000000318200089A00198E00000000000000089A00109200427908089600198E00000000
+00D7000000005265E65265E65265E608960008960008960008960008960008960008960008960008
+9600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E65265E65265E652
+65E60000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E600000000000000000000BA00198E00109600218A00298600089A00000000000000
+089A0000A60000BE0000B20000C20000CE000000000000005265E60000000000005265E600000000
+000010920019920000AA0000CE0000000000000000BA0000D70000A2004A750800A60000D70000D2
+00000000000000198E00298600218E00198E0000000000000000BE0000C60000000000000000A200
+089A0000AE0000CE00109600218E003182004A750800000052710829860000000000C20000B60000
+CE00000000089600318200736519527508636D104279004A75085A6D106B69197365197365190000
+00000000FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+736519736519736519218A00636D107365193A7D004A7508000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF0000000000C60000BE0000CA0000C60008960010960000A600009E0000A20000B60000B6
+001092004A7908298600199200218A00198E00318200736919427908198E00218A00218A00199200
+109200089A0000000010960000A20000A600009E0000B200198E00427900298600198E0008960000
+0000000000000000000000000000298600198E0010960000000000000000AE0000BE001092001092
+00198E00198E00298600298600198E00198E003A7D00218A0000C60008960000BE0000000000E700
+000000000000009E00298600298600089A000000000000000000001096006B6919198E003A7D0042
+7908089A0000BE000000000000000000005265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896
+000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+000000005265E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E6000000
+5265E65265E65265E65265E6000000000000000000000000000000000000109200089A00198E0021
+8A00109600000000109200218A00009E0000BA0000C60000D20000D2000000000000005265E60000
+0000AA000000005265E6000000009E00089A0008960000000000E70000000000B60000AE00427900
+4A750810960000B20000D20000DB000000000000003A7D00218A0000000000000010960000C60000
+000000BE0000AA0000000010920008960000B20000A60000BA00427D00318200000000218A003A7D
+0010960000000000CE0000BE0000D700000000009E004279007B65195A6D105A6D10636D105A6D10
+6B69197B69197B6D216369106B6919000000000000636910000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF000000007365196B69107365195A71100896005275085A6D10427900427900000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF0000000000B20000BE0000AE00089A0000C20000A600109200
+00BA0000B20000AE0010920000B600218A00198E00198E001096003A7D003182004A75083A7D0029
+8600109600198E0010920000AE00218A0000000000AA0000A60000A200009E00109200218E004279
+08318200109600318200218E000000001992000000003A7D00218A00109200089600218A00000000
+00C200198E00089A00218A00089A003A7D00318200298600218A003A7D00218E0010920000D20000
+BA0000000000000000DF0000000000D2000000003A7D004A7508427900298A001992004279003A7D
+00218A00218A000000000000000000000000000000000000000000005265E65265E65265E6089600
+089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E65265E65265E652
+65E65265E65265E60000000000005265E65265E6000000000000009E0000DB0000000000DB0000DB
+00000000000000198E00218A00109200000000009E0000BE0000C20000AA00089A0000DB0000CA00
+0000000000005265E600000000AA000000005265E600000000CA0000D70000000000000000000000
+000000D20000C2004A75084A750810960000B20000AE0000DF0000000000000000000000000000B2
+0000B20010920000C60000A60000000000A200000000089A0000B20000A60000BA0000BE003A7D00
+4A750800000019920031820000000000BA0000DB0000A200009E0000A200000000198E0010920031
+82004279005271085A6D106B69196B69197365196B69197B71217365196B69106B6910000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF000000005A6D107365197365195A7110218A006369105A6D10
+636D10000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000BE00009E0000
+AE0000A60000A600089A0010920000B60000AE0010920000BA00198E00109200109600089A003182
+005A6D10427908298600298600198E00109600089A00089A00009E0000000000B20000A20000B600
+109200109600109200318200427900199200298600198E00218E00000000000000318200198E0010
+9600298600198E0000000000B200198E00218A00218A00198E00218A00318200298600218A00218A
+0010920000A20000D70000000000E70000E70000000000D700089A000000003A7D004A7508527110
+5A6D1042790800A60000000000000000000000000000000000000000000000000000000000000052
+65E65265E65265E60896000896000896000896000896000896000896000896000896000896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284
+424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896000896000896000896000896005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000C60000AE00
+218A00000000000000009E0000CE0000000019920019920000BA0000000000A600009E0000A60000
+D70000D70000B20000AE000000000000005265E600000000000000BA000000000000000000000000
+0000AA00009E0000CA0000E30000BE00009E0000AA003A7D00527508218A0010920000B60000D200
+00000000DB0000D70000000000000000000000A20000000000A60010960000CA0000000000AA0010
+920000A200198E0000A200218A00000000318200089600000000089A0000C20010960000BA00089A
+0000BE000000002986005A71105271103A7D005275087365197365195A6D106B69197369196B6919
+636D10089A00109600000000000000FFFF00FFFF000000000000005271085A6D1063691073651973
+6519009E00636D10527508527108000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+0000000000A60000A60010960000A600009E00199200009E0010960000AE0010920000BA00089A00
+089A00198E002986003A7D00636D105275083182003182003A7D00218A00109200089A0010960000
+A60000A60000B200089600109600218E00218A004A75083182003A7D003A7D000896001096000000
+00089600000000000000000000089A003A7D0000000000A600218E00089A00198E00218A00318200
+298600318200218A00198E00198E0000C60000CA0000000000E30000E30000000008960000B20000
+000000B6004A75084279004A7508218A00000000000000000000000000089A0029860000D70000A6
+003A7D00009E000000005265E65265E6000000089600089600089600089600089600089600089600
+089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FF
+FFFF848284FFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E60000005265E65265E65265E65265E600000000000000000000
+000000AA0000D200089A00218A0000A20000000000A60000BA0000000010920000B60008960000BA
+0000000000DF0000B20000AE0000AE0000B20000C2000000000000005265E600000000000000BA00
+00DF0000000000C20008960000C60000DB0000AE0000AE0000B60000D70000AA00218A003A7D003A
+820000CE0000AA00089A0000000000E70000AA0000B600009E0000AE0000000000B20000A20000C6
+0000CE0000D20000000000BA0000A200089A00089A00000000318200427900427900000000109600
+00A600009E00109600009E0008960000000000000000000000A200198E00298600636D10636D1063
+6D107B65197B7121736519527108009E000000007365190000000000000000005275082986005271
+085A71107365197B6519736519109200527108636D107365195A7110000000FFFF00FFFF00FFFF00
+FFFF0000000000000000000000A60000A60000A20000AA0000AA0000AE0010920000BE0000BE0000
+BA0000BA00009E0000B600198E001096003182003A7D007365195A6D10427900318200198E00198E
+0000BE00009E0000A60000A600089A00109200089A00218E00109200218E00198E00298600198E00
+427D00109200000000218A00218A00218A00009E00198E00000000089A00000000109200218A0010
+96003A7D00218A00089600318200218A00109600298600009E0000A20000BA0000000000DF000000
+0000C600089A00218A0000AA00000000009E000896000000000000005A71105A7110636D10427908
+298600427900218A0000AE000000000000000000005265E600000000000008960008960008960008
+9600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008
+96000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E60000000000
+0000000000000010920000A200218A00218A0000AA00199200109600000000198E00198E00000000
+10920000A60000A60000AA0000000000C20000A60000D20000AA0000C60000D70000000000000052
+65E600000000C20000E70000CE0000000000DF0000AE0000D70000CA0000DF00089A0000AE0000C2
+0000DB001096002986003A7D00218E0000AA0000AA0000000000B60000E70000DB0008960000C600
+08960000B200000000000000000000000000000000009E00109200089A00009E0000000010960042
+79084A7908318200000000089A00009E0000B20000000000CE00198E003A7D003182000000001092
+003A7D00198E003182005271087365196B69197365190000000000007365197365190000004A7908
+636D103182005A71105271087B65196B69107365196B6919089A00427900527508527108636D1000
+0000FFFF00FFFF00000000000000FFFF00FFFF00000000000000109200089A00009E0000A60000A6
+0000B600109200109200009E0010960010920000BA00198E003A7D004279004A75084A7508318200
+298600218A00089A00218A0000BE00009E00109200009E00089600198E00298600198E00198E0019
+9200298600198E00198E00298600109600000000000000089600198E00109600109200089A000000
+0000C200109200089A003A7D00218A00218A00298A00298600298600218A00089A0000C600089600
+00000000E30000000000000000C200298600218A00089A000000000000000000003A7D0042790873
+651910960000B20000A20000B60000AA0000A6000000000000000000000000005265E60000000000
+00089600089600089600089600089600089600089600089600089600089600089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE0896000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E6
+5265E600000000000000000000000000000000CA0000B20000C6003A7D0019920029860000A20000
+AA0000000000000000CE0000C60000DF0000C60000000000000000C60000B20000A20000A20000BA
+00089A000000000000005265E600000000000000000000000000000000000000BE0000DB00089600
+00C20000CA0000AE0000AE0000C60000A2003A7D00198E0000AE0000B60000A20000000000AA0000
+C60000BE0000CE0000A600000000000000FFFF00FFFF0000000000000000000000000000BA001096
+00109600218E0000000031820042790800000000000000AA00198E00109200089A0000000000C600
+19920031820031820000000000A2005271106B69105A71107365197365190000004A75086B691963
+6D105A6D100000003A7D005A6D105A6D105271085A71107365197365196369105A6D102986005271
+084A7508527108636D10427900000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+00AE00089600009E00109600009E00199200198E00109200089A00009E00198E0019920029860052
+7508736919427908218A00318200218A00218A0010960000B600009E0010920000BE00198E00198E
+00109200089A00218E002986004279001992003A7D00000000000000FFFF00FFFF00000000000000
+218A00218A00218E00000000000000218E00089A00199200298600298600298600218A00198E0019
+8E00009E0000D70000000000DF0000000000000000D2000000004A75084A790800A2000000003182
+002986004A79083A7D00527108318200218A0000A600089A0000BE0000000000D20000C600000000
+00000000000000000000000008960008960008960008960008960008960008960008960008960008
+9600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFF
+FFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000
+000000FFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E60000005265E65265E65265E600000000000000E700089A0000AE0010960000D200089A000896
+00218E00318200198E0000BA0000000000000000000000DB0000C20000000000B20000C60000D700
+00CA0000C60000C60000B60000AA0000BA0000000000000000000000C20000CA0000DF0000D70000
+000000BA0000AE00009E00089A0000D20000AA0000BE0000B60000A60000BE0000A60000A200089A
+0000C60000000000CE0000C60008960000AE00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+000000FFFF00000000199200109200089A00000000000000000000298600218A00218A00009E0000
+9E00218E00198E00000000198E00218A00318200427900000000009E004A75086369100000000000
+00527108636D10736519636D10000000318200427D007B69195A6D105275085271105A6D10736519
+6369105A6D104279085271084279005271104A75084279083A7D00000000FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF0000000000BE0010920000BA0000BA0000BE0000BE00089A00009E00198E00218E
+00089A002986003182003A7D006369103A7D003A7D00218A003A7D0029860010920000B200218A00
+218E00089600218E00109200009E0000BA00198E00298600427900089A00000000FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00000000089A00000000000000089600000000000000218A003A7D00218A
+003A7D00218A00109600198E00089A0000000000E30000000000C20000BE0000AE00000000527110
+4A75083A7D00000000736519218E00199200009E00298600198E0042790042790000A60000B20000
+000000A20000BE0000A20000000000000000BE000000000000000896000896000896000896000896
+00089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84
+8284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E600000000000000000000CE0000B20000C20000A600
+00D70000BA00109200089A00198E00298600009E0010960000A600000000000000009E0000B60000
+000000B60000C20000D70000CA0000D70000B60000C60000AA00009E0000000000000000000000CE
+0000D70000BE00009E0000000000DF0000AE00089A0000B60000C60000DF0000DB0000C20000A200
+00CA0010960000A60000AA0000AA0000000000B20000A60000AA0000A600000000FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00000000FFFF00000000009E00109200218A00000000000000298600218A
+00298600198E0000BA00109600198E00198E00000000198E00198E00218A00318200427900000000
+218A000000005A6D105271105A6D105271087365190000000000004A790800BA005A6D107365195A
+71107365195A6D10736519636D10218A004A75084A75084279005271085A6D103A7D00000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000218A00109200089A00109200089A00
+089600109600198E00089A00218A002986002986004279002986003182002986002986007369197B
+7921198E00089A000896001992001992003A7D00109200199200198E00089A00198E00218E00198E
+00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000198E00000000218A003A7D00
+298600000000298600318200298600318200218A0000AA0000C60000000000DF0000000000B60000
+A600000000109600427900736519318200000000527508218A0031820000C20000D20000CA000000
+0000000031820000000000000000D20000A20000A60000000008960000B6003A7D00000000089600
+089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000
+00000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600
+0896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000B20021
+8A00089A00198E00198E00109600198E003A7D002986001096003A7D0000A200089A0000D2000000
+0000D20000E70000C20000000000CE0000CE0000B20000D70000BA0000D70000B600000000000000
+00000000000000000010920000D70000D70000DB0000C200000000089A00009E0000B60000B20000
+AA0000AA0000B20000CE0000AE0000B20000A600009E0000B200000000109600198E001096000000
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00000000199200089A00
+000000089A002986003182003A7D0029860019920019920010920042790000000000000029860019
+92003182002986004279080000000000002986005271085271085275085275080000005271085A6D
+10218A005275087B65197365195A6D105A7110636910636D103A7D006369105A7110527108636D10
+4A7508298600000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000198E0008
+9600199200109200218A00089A00218A00298600198E003182003182002986003A7D003182003A7D
+00298600198E00318200199200089600089A00009E00109200089A00089A00218A00298600198E00
+298600218A00218A00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000019
+8E00000000218E00198E00198E00298600000000218A00298600109200218A0000B20000000000DF
+0000000000BE00009E001096000000005271082986005271084A79080000004A7508298A005A6D10
+527508427D00089A00000000000000000000000000198E00218A0019920000CA000000003A7D0000
+9E000000005265E60896000896000896000896000896000896000896000896000896000896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896000896000896000896000896000896005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+0000000000C600009E00198E0000BE0000B600218A0000AA00198E00009E0000B20000BA00109200
+089A00009E0000000000000000000000000000000000000000C20000C20000CA00009E0000000000
+000000000000000000BA0000D20000000000000000000000DB0000BE0000BA0000C2000000001096
+0000DB0000AA0000AA0000DB0000AA0000DF0000B20000BE0000A200218A00198E0000A600000000
+00A20000AA0000B200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FF
+FF0000000000BE00089A00000000109600218A00318200318200198E00318200298A00089A00198E
+00089A0000A2000000002986003A7D003A7D003A7D00298600218A00109600218E004279004A7908
+6369100000005271085271103182005A6D105A6D107365195A6D105A6D10527508736519427D005A
+71107365195A6D104279004A75084A7508427900000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00000000198E00089A00089A00109600218A00298600198E002986002986003A7D003A8200298600
+3182003182004A7508298600298600198E00089A00318200109600109200009E00109600218A0008
+9A0010960000BA001992003A7D00109200089A00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00000000218A00000000089600198E000000000000000000003A8200298600199200
+00AA0000000000DF00000000109200198E0000D70000AA000000007B6519009E0052750829860000
+00002986004A7508089A00089A00009E0000000000000000000000000000000000000000A200009E
+000000000000000000000000005265E65265E6089600089600089600089600089600089600089600
+089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+00000000000000000000000000000000000000000000CE0000C20000DF0000DB00218E00089A0000
+A60000D20000BE0000AE00089A000000000000005265E600000000000000E700009E0000C20000CA
+0000E30000000000BE0000C60000AE00089A0000D70000BA0000000000000000000000A20000BE00
+00D70000CA00009E0000000000B60000A200009E0000D700009E0000A60000A20000C60000A60019
+8E0000AE0000BE0000000019920000A20000B200089A00000000FFFF00FFFF00FFFF00FFFF00FFFF
+00FFFF00000000FFFF00000000089A00109200000000218A003A7D00298600318200318200218A00
+3A7D00298600089600218A00109200218A00198E000000000000000000000000002986003A7D0029
+8600089A003A7D004279084279080000004A79084A75085A71105A6D10527108636D105271085275
+085271087365194279004279004A75084A75083182002986004A7908318200000000FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000198E003A7D00089A00089A003A7D002986002986003A7D0042
+79004A75085275083182003A7D00318200318200298600298600298600109600527108089A00218A
+00089A0000BA00198E00109200198E001092000896002986003A7D001092004A7508000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF00000000199200199200000000000000000000298600218A0000
+0000000000218A0000A20000DF0000000000000000A600198E0010920000D70000BE000000002986
+005A711042790000AA000000001092000000000000000000000000000000000000000000005265E6
+5265E600000000000000000000BE0000AA0000AA000000005265E65265E608960008960008960008
+9600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008
+96000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000000000000000E3000000000000000000001092
+00089A0008960000CE0000D20000A20008960000AE0000DB000000000000005265E6000000000000
+00BE00009E0000C20000000000000000A20000BE0000A20000DB0000AE0000C60000CA0000000000
+000000000000C60000C20000C20000CA0000C60000000000DB00009E0000DB0000A60000DB00089A
+0000B20000B20010920010920000BA00298600000000109200089A0000BE00089A00000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00000000009E00000000000000089A0019920019
+8E002986003A7D00298600298A003182003A7D003A7D00298600298600318200199200298A00218A
+000000003A7D00218A003A7D00218A003182004279000000004279005A71105271085A6D10636D10
+5A6D10636D10636D107365196369104279003182004A75085A71104279004279083182004A790800
+0000000000000000000000FFFF00FFFF00000000000000298600109600218A00198E001992003182
+003182003A7D003A7D006B69107365196369107B6D215271084A7508298600218A00318200218A00
+3182004A7508109200198E00109200218A00089A00218A00199200218A00218A00218E00427D0029
+8A00318200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000218A00298600218E001096
+00198E00298600198E00199200000000000000000000000000000000009E000896003A7D00089A00
+00DB0000DF00000000198E00109600427D0008960000DF0000000000000000000000000000000000
+00000000000000000000000000005265E60000000000000000000000000000000000005265E60000
+00089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+000896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E60000000000005265E6000000000000000000000000
+00000000000000000000000000000000000000CA0000BE0010920000CA0000CA0000000000000052
+65E65265E600000000000000CE0000D70000000000000000CE0000A20000A60000AA0000BE00089A
+0000AA0000CE0000C60000000000000000DB0000D70008960000D70000B20000000000CE0000C200
+009E0000AE0000DB0000CA00009E0000AE0000A60000A600199200000000109200218A00218A0010
+9600109600198E00000000000000FFFF00FFFF000000000000000000000000000000000000000000
+00000000198E00199200089A003A7D00318200218A002986003A7D00298600298600298600318200
+427908318200318200218A002986000000000000003182003A7D003A7D003A7D0000000042790031
+82006369105A71104A7508527508527108636D105271085A6D10527108318200636D105275084A75
+084A7508318200298600000000109200218A00199200000000000000298600298600298600218A00
+3A7D003A7D003182004A75083A7D003182007365197365197B6921736519636910527108636D103A
+7D00298600298600089600427900427900218A00218A001096001992002986002986004279003182
+003A7D00218A00218A003182004A7508198E00000000000000FFFF00FFFF00000000000000198E00
+318200089600218A00198E00198E00199200198E00198E00198E0000000000E30000000000000008
+96003A7D0042790000CE0000CE0000AE0000000000A2004A750800A600089A0000B200000000009E
+000000000000000000000000000000000000000000000000000000005265E6000000000000000000
+5265E65265E65265E600000008960008960008960008960008960008960008960008960008960008
+9600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482
+84424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E600000000
+00000000005265E65265E65265E65265E6000000000000000000000000089A000000000000000000
+000000000000005265E65265E65265E600000000CE0000DB0000000000DB0000C60000AE0000AE00
+00CE00009E0000AA00009E0000DF0000B60000C60000000008960000D70000C60000D70010920000
+CE0000000000000000B60000B20000A20000C60010960000C200089600009E00198E00009E000000
+00218A00218A00109600199200218A00218A00089600218E00000000000000000000000000000000
+000000089A00218A00000000109600009E00318200199200218A002986002986002986002986003A
+7D003A7D004A75082986003A7D004279003A7D00218A002986003A7D002986000000002986003182
+003182000000003182003A7D004A75085271084A75085271085A6D104A75085A6D105A6D104A7508
+5271086B69194A79084A7508427900427900000000089A00218A002986003182003A7D0029860031
+82003A7D002986003A7D003182002986004279002986004279002986007B69217B71217365197365
+19636D10736519427D004279003A7D00298600218A00427908109600089A00198E00198E00218A00
+4A79083182003182003182003182003A7D003A7D003A7D004A7508198E00218E00218A0000000000
+0000318200198E00198E003A7D00218A00218A00318200298600298600199200198E00218A000000
+00000000009E00089A002986004A75084A750800D200089A0000CA00000000000000109200527508
+218A00198E000000003A7D005A6D10427908318200636D104A75083A7D0000B20000BA0000000000
+00005265E65265E60000005265E65265E65265E65265E60896000896000896000896000896000896
+00089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E60000005265E60000000000005265E65265E65265E65265E65265E65265E6000000000000000000
+00000000E30000CA000000005265E65265E65265E65265E600000000000000CA0000000000C60000
+BA00009E0000CE00009E00089A00198E0000A60000B60000DB00089A0000000000000000A60000C6
+0000D20000B20000DF0000AE0000B20000D20000DB0000D20000A20000CE0000AE0000A60000A600
+00A600109200109600000000089A00198E00198E00298600218A00198E00199200218E00089A0010
+9600000000000000218A00089A0000BA0000B600000000089A00109600218E003A7D001992002986
+00298600298600218A002986003A7D003182004A75083182003A7D003182003182002986003A7D00
+318200000000427D003A7D000000000000004279003A7D005275085A711052710852710852710852
+71085271105A71103182004A79084A75085271083A7D003A7D00000000089A00298600218A00089A
+00218A00427D002986003A7D003182003A7D003182003182003A82004279004A75083A7D005A7110
+7B6D217B65197B69196B69107B71217365194279003A7D00318200298600218A00198E00198E0010
+9600198E003A7D00089A000896003A7D003A7D003182003A7D004279003182004A7508198E003A7D
+00089A00009E002986000000000000000000004A75082986001992003A7D00218A00298600298600
+199200198E0000000000000000000029860000A20052750852711029860000BA00198E0000000010
+92003A7D000000004A750829860042790042790000000000000000000000000000D20000C200089A
+0029860000A6001092000000000000000000000000000000005265E65265E65265E6089600089600
+089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600
+0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E60000005265E65265E65265E65265E60000000000000000005265E65265E652
+65E60000005265E65265E60000000000000000000000005265E65265E65265E65265E60000000000
+0000000000DB0000C60000B60000CE0000C60000C60000C6001992003A7D0008960000DB00000000
+00000000DF0000AA0000CA0000D20000AA0000DF0000A20000DB0000C60000B20000CA0000AA0000
+D20000A200109600089A0000A600109200198E00000000199200298600298600318200298A00298A
+00298600298600199200000000089A00218E00218E00198E00218E00198E00000000109600109600
+198E003A7D00198E002986003182004279002986003182003A7D004279003182003A7D004279003A
+7D003A7D003182003182004279004A79082986000000000000000000004A79084A75085A6D104A75
+084A7508527108636910636D107B65194279004279084A79085A7110318200000000000000089A00
+1092001096003A7D002986002986004A75083A7D003A7D004279004279084279084A790842790052
+71084279004A75085A71107B75217369196B69107365197B71217B71217365194279003A7D002986
+003A7D00218A00199200089A003A7D00198E00218A00218E00427D004279003182003A7D004A7508
+318200218A00298600198E00218A00089A0029860000C200198E00109600000000199200198E0010
+9600218A00218A003A7D0008960000000000D20000B600000000109200198E005271083182001096
+0000C20000AE000000004A75083A7D004A75080000003182005A6D105A6D1010920000D200089A00
+00D7000000000000000000000000000000000000000000000000000000000000000000005265E652
+65E65265E65265E6089600089600089600089600089600089600089600089600089600089600D6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFF
+FFFFFFFFFFFFFFFFFF848284848284848284848284848284848284848284FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000
+00000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6
+D2CE0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E60000000000000000000000005265E65265E65265E65265E60000
+000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E600000000000000000000AE0000B60000DB0000BE00218E0000BE0008960000AA00089A0010
+920029860000A60000000000CE0000000000DB0000DB0000C60000D70000B20000AA0000A20000DB
+0000B20000BE0000BA0000A20000A600109200009E00109200109200000000218A00218A003A8200
+2986004A7908298600318200298600000000000000199200199200198E00198E00218A00198E0021
+8A00000000089A00198E00198E00198E00198E00298600298600318200218A003A7D003182002986
+003182003182003182004A79083182002986004A75080000000000000000002986003182003A7D00
+0000002986004A75085275084A7508636D107B65195275084A75084279005271085275083A7D0000
+00004A7508298600109600109200298600218A002986003182003182003182004279004A75083182
+003182003A7D003182007365194A75084279007365197B75217B71217B71217365196B69197B7921
+7B69193182002986003A7D00298600298600199200198E00089A00199200198E00199200218A0031
+82003A7D003A7D003182003A7D00198E00218A002986001992003A7D003A8200198E00218A003182
+00000000000000000000000000218A00198E00089600000000218A0019920000BE00000000109200
+427900527108218A00198E0000BA00089A00000000199200318200199200000000199200636D1008
+9A007365194A790800A20010920000C2000000000000000000000000000000000000000000000000
+000000000000005265E65265E65265E65265E6089600089600089600089600089600089600089600
+089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442
+4142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8482
+84FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF0000000000
+00000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000
+000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000000000005265E6
+5265E65265E60000000000000000000000000000000000005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E600000000000000000000AA0000C20000D70000CA0000D70000BE
+0000000000000000000000AE0000000000000000A60000000000CA0000B60000C60000B60000B200
+00C60000CE0000A200009E0000AE0000CE0000C60000A20000AE0000B200009E00089A00089A0000
+0000218A00218A002986003182004A79083A7D004279000000000000002986002986002986001992
+00198E00218A00198E00218A0000000000BA00298600198E00218E00198E00318200218A003A7D00
+3A7D004279083182004A75083182004279080000000000000000000000000000004279084A750831
+8200318200218A004279000000003182003A7D004A75084A75085271087365194279005271084279
+003A7D003A7D003A7D00000000318200089600109600218E002986002986002986003A7D00318200
+4279004A75083182003A7D003182004279003182004279004A7508527508636D107365197B71217B
+69217B69217B6D21736919427900218A003182004A75082986003A7D00198E00298600198E002986
+00199200298600218A00298600198E00318200218A003A7D0010960029860000BE00218A004A7908
+3A7D00218A00298600298600298600218A0010960029860000000000000000000010960008960008
+9A00000000218E003182005A7110527508218A0000B60010920000DB000000004279005271087365
+190896000000000000000000003A7D00427908298600527508218A0000BA0000DB00000000000000
+0000000000000000005265E65265E60000005265E65265E65265E65265E608960008960008960008
+9600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF00
+0000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+00000000000000005265E600000000000000000000000000000000000000DF000000000000000000
+005265E60000000000005265E65265E65265E65265E65265E65265E600000000DF00000000000000
+00000000000000000000000010920000000000A60000000000A60000B20000A20000CA0000000008
+960000D70000DB0000D70000DB0000AA0000BA0000A200089A0000C60000B200218A0000C60000A6
+00089A00089A00218A000000002986002986002986003A82003182003182000000004279084A7508
+318200218A00089600218A00198E00109600009E0019920000000000B600218A00218E00198E0008
+9600218A003A7D002986003A7D003A7D003A7D004279080000000000003A7D003182004279083A7D
+003182004279083A7D003A7D00427D003A7D003A82000000004A75083182003182005A71104A7908
+5A6D104A75084A75084279083A7D003182000000003A7D00218A004A7508198E00198E0031820029
+86002986004279084A75083A7D004A75085271085275083A7D002986004279003182005275084A75
+085271087365197365197B69217365196B6919218A00218A002986004A75085271084A7508298600
+298600298600109200298600089A003A8200198E000896002986002986003A7D003A7D0008960029
+8600218A00198E003A7D00009E00427900218A002986004279003A8200318200218A00198E00009E
+0000A200198E00298600009E0000BA000896002986004A75085A6D10298600089A00089A0000CE00
+0000000000000000000000003A7D0052710800DF000000000000006369103A7D0063691000A60029
+8A003A7D0029860000DF0000CA001092000000000000000000005265E65265E65265E65265E65265
+E6089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFF
+FFFF848284000000000000000000000000000000848284FFFFFF848284FFFFFF848284FFFFFF8482
+84FFFFFF848284FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF0000000000
+00000000000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896
+000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E60000000000000000005265E60000000000000000
+005265E65265E60000000000000000000000005265E600000000000000000000000000D200000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000008960000DB00109600089A00218A0019920000A20000B200109200089A
+00009E0000A20000000000D70000D70000AE0000DF0000A60000AA0000A20000CE0000A20000AE00
+00AA00009E0000A20000AA00109200109200298A00218E000000002986002986002986004A790800
+0000000000318200427D004A7508298600298600298600199200198E003A7D00109200000000218A
+00109600009E00089A001992003A7D00218A00298600318200318200318200000000427900427900
+4279004279083A7D004A75084279084A7508318200298600318200427D00218A0000000000000031
+8200427900427D004A75084279085A6D104279084A75085275083182000000003182002986002986
+00109600298600218A003A82003182003182003182003182004A75084A75084279004A75083A7D00
+318200427900427D004279004279087365195A6D10527110636D103182003A7D0029860029860031
+82003A7D00318200218A00298600218A00218A004279004A7508427900318200198E003A8200427D
+003A7D003A7D00198E00198E00089600298600218A003A7D003A7D00318200318200318200298600
+3A7D00218A00198E0000C600089A0029860000A20000A600089A00218A002986003A7D0031820019
+8E0000BA00198E0000A60000000010960000D70000BA0000000000B200218A0000DB0000C6000000
+00218A0029860031820000B20000C20000C600318200089A000000000000000000005265E65265E6
+5265E65265E65265E65265E608960008960008960008960008960008960008960008960008960008
+9600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482844241
+42FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000
+FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CED6D2CE0896000896000896000896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000000000
+00000000000000000000000000000000000000000000000000DF0000000000000000000000DB0000
+E700089A0000000000AA0000CA0000C60000C20000BA0000CA00009E0000000008960000B6000000
+0000000000000000000000000000000000AE0000000000D70000AA0000C60000CE003182004A7508
+109200089A00218A003A7D00218A0000000000000000CE0000D70000C20000AA00089A0000CE0000
+CE00009E00009E0000A20000B20000A200009E0008960010920000BE00089600089A00000000218A
+002986002986000000000000004A75084279003A7D003A7D004A7508298600318200218A003A7D00
+198E00109200000000199200198E00009E00089A001096003A7D00218A003182004A750800000000
+00003182004279004A75084A75084A75085271084A75084279004279003182003A7D004A75084279
+003182002986003182000000003A7D004A7908427D004279004279004279083A7D00427900318200
+0000002986002986003A7D003A7D00298600427D004279004A79083182003A7D0031820052710852
+71084A75084A79084279004279003A7D003182003A7D005275084A75084279004A75083182002986
+00298600218A002986003A7D00218A00218A00218A002986003A7D00218A00198E00427900427900
+318200298600298600298600218A003A7D00218A00198E00198E00318200198E003A7D003A820031
+82003A7D003A7D00218A00298600198E0000A200198E00198E001092001092001992003A7D003A7D
+004A7908427D0010960000B600089600298600109200000000427900089600009E0000DB00000000
+00000000DF0000C60000DF0000000000000000B20029860000CE0000E30000000000000000000000
+00000000005265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000
+00000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFF
+FFFFFFFF000000FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E652
+65E60000000000000000005265E600000000000000000000000000CA0000000000000000CA000000
+0000000000000000000000E30000AE0000000000B20000D20000C20000A60000CA0000D700000000
+009E0000B600089A0000A60000DB0000CA0000000000000000BE0000D20000000000000000AA0021
+8A00218A003182004A7508009E0010960010920031820031820029860000000000000000D70000A2
+0000B200089A0000A20000C60000CA0000C200089A0000B20000A200089600109200109200199200
+109600089A000000003A7D003182000000000000004A75083182003A7D004279005271083182003A
+7D003A7D00199200427900089A00109200000000198E00199200109600089A00198E002986002986
+003A7D004279000000003182004279005275085275087365195A6D10636D105A6D105A71105A6D10
+4279003182003182004279003A7D003A7D004279000000004A79083A7D004A75084279084279003A
+7D004279084279000000003A7D00218A00298A003182003A7D003A7D003182003182003182004279
+00427900527108427D005275085A6D105271105A71105275084279083182003A7D004A75084A7908
+4A7508318200318200318200218A003182002986002986002986003182002986002986003A7D003A
+7D00198E00427908427900318200218A004A7908298600298600199200009E00218E00298600198E
+00218A002986003182003182004279083A7D00298600218A0000B600109200089A00199200109200
+427900109600218A003A7D00527508298600218A00218A00198E0029860000B2000000005A71107B
+6921218A0000AE0000AA0000000000000000000000000000000000000000C200089A003A7D00218A
+000000000000000000000000005265E65265E65265E65265E65265E65265E65265E6089600089600
+089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF8482848482
+84848284848284848284848284848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000000000
+FFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600
+0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+000000000000000000005265E6000000000000000000000000000000000000000000000000000000
+00D20000CE0010920000B60000AA0000000000000000DB00009E0000000000A60000D70000C20000
+BE00089A00000000009E0000DB0000BE0000DB0000B20000C60000AE0000000000D20000DF0000C2
+0000DB0000D200000000089A00109200198E00298600218A00009E00198E00089600298600218A00
+00000000A20000AE00009E0000CA0008960000AA0000B200089A0000AE0000A20000B20000AA0010
+9200009E0010920000BA00198E00109600000000000000000000199200318200427D004A75084A75
+084279085271085275083A7D00318200198E00198E00199200089A00000000199200218A00089A00
+089A00109200109600218A003182000000003A7D003A7D005A6D106369107365197B71217365197B
+69217365197B65197365195A71104279003A7D002986004279003182004279000000003A7D004279
+083A7D003A7D004279005275080000000000000000003A7D003182002986003A7D00427900318200
+4A75084A79084279084279004A75085A71105271105A6D106369107365195A71105A71105A6D104A
+75084A75083182004A79084A75083A7D00298600318200218A002986003A7D00318200218A00218A
+00318200298600218A00298600199200427900298600218A003A7D00298600218A002986003A7D00
+089A00198E002986003182003182004279083A7D003182003A7D00318200318200198E0010960019
+8E00298600089A00198E002986000896002986003A7D00427900298600218A00218A00198E003A7D
+00218A000000004279003A7D003A7D003A7D00109600009E0000E30000CE0000E30000E300000000
+0000000000000000000000000000000000000000000000005265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600089600089600089600089600089600D6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08
+96000896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E60000000000005265E65265E65265E65265E65265E6
+5265E60000000000000000000000000000000000005265E600000000000000000000000000000000
+000000000000BE0000000000A20010920000A20000A60000A20000A60000CE0000DB0000DB000000
+0000A20000D20000CE0000B20000000000000000CE0000A20000AA0000BA00009E0000CE00109200
+00000010960000C20000C60000D200009E0000000000AE0000A20000B60000A60000BE0000AA0019
+8E0000CA0008960000AE00000000009E0000BA0000CE0000BE0000BE0000BE00089A0000BE001096
+0010920000A600009E0000B20010920000C200298600218A00000000000000198E00427900218A00
+089A002986003A7D003A7D003A7D004279003182003A7D00427900218A00198E00199200198E0000
+0000198E00089600089A00427900198E002986003A7D003A7D000000004279004A75086B69196B69
+19636D107365197369197B69217B6D217B71216B69107365197365194279084279083A7D00298600
+3182000000003A7D003A7D003182003182003182004279000000004A79083A7D003182003A7D0029
+86003182003182003A7D003182004A75084279003A7D00427900636910636D107B69197B75217B6D
+215A6D105A6D105A6D104279004279084279004A75083182003A82002986003A7D00298600298600
+218A00218A003A7D002986004A7508318200218A00218A00218A004A75082986003182003182004A
+79082986002986002986002986002986002986002986002986005275084A75080000000000004A75
+08218A00198E00298600198E00109600427900218A00218A00218A00218A00318200427900427908
+427908198E00198E00218A00198E0000000000000000000000000000000000000029860000D70000
+9E00009E0000E30000E30000000000E7000000000000000000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600089600
+089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284
+8284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E600000000000000000000000000000052
+65E65265E65265E600000000000000000000DF0000DB00089A0029860000000000000000000000C2
+0000000000000000000000000000DB0000C20000000000000000AA00089A003A7D003182003A7D00
+318200009E0000AE0000DB0000000000000000BE0000000000A20000DB0000A20000AA0010960010
+960010920000BA0000000000DB00009E0000AE0031820000AA0000CE0000000000A200218A002986
+0008960010920000B20000A60000AE0000C60000000000000000000000AA0000A20000C60000AE00
+089A00009E0000AA0000C60010960000A600218A00089A0000B600089600199200000000198E0021
+8A00198E00218E00218E00089600198E003182003A7D003182004A75085A71103182004279002986
+00318200109200109600000000218A00218A00109600199200218A002986002986000000003A7D00
+3182004279007365196B69197365197B71217B79217B75217B7D217B71217B71217369197365196B
+69103182003A7D004279004279000000003182004279083182003A7D000000000000004279083A7D
+003A7D004A75083182003A7D003182003182003182004A7508298600427908318200427908527108
+5A6D107B6D217B75217B69217B65195A6D105A6D105271084A75084279084279083182003A7D0031
+8200298600298A002986003A7D002986003A82003A7D003182003A7D00298600298600218A003182
+00318200298600318200298600298600298600298600218A00218A003A7D00218A00318200000000
+000000FFFF00FFFF00000000000000199200298600298A00218A003182002986003A7D003A7D003A
+7D002986003A7D00427900318200218A00089A00199200089A0042790019920000DB000000000000
+0000000000CA0029860029860000BE00009E0000D20000DF0000DB000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008
+9600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000000000E3
+0000B600000000000000000000000000000000000000009E0000AA0000BE00298600427900427908
+29860000C60000AA0000A20000000000000000B20000B20000A60000A20000BE0008960000000000
+9E0000BA00109600218E003A7D00218A00427D0010960000CE000000000000000000000000000000
+00000000089A0010920042790029860010920000000029860000BE0000B20010960000B200109200
+00000000000000BA0000A20008960000D70000A20000DB0000CE00000000000000089A0000AE0000
+9E0010960000BE0000AE0000C60000C200089A0008960000B20000B20000B200109200009E0000BA
+00000000198E00198E00218A00109200199200218E00218A00198E003A7D002986007365195A6D10
+4A75085275084279083182003182003A7D00199200000000218A001096001092003A7D00218A0029
+86002986000000003A7D005A71105A71106B69197365197B75217B6D217B7D217B7D217B7D217B79
+216B69197B75217B79217B75217B71214279084279003182003182000000000000003182003A7D00
+0000003182004A75083A7D003182003182004A79084A79084A75083A7D005275083A7D003182004A
+75084279084A75085A6D105A71107365197365196369107365195271084A75083A7D003182002986
+004A75083A7D004A75083182003182003182003A7D003A7D003A7D002986003A7D004279003A8200
+3A7D00218A002986003182004279083A7D003182003A7D00218A00318200089600218A0029860029
+8600318200000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000218A00218A00218A003A7D
+002986004279004279004279083A7D004A7508427900427900318200199200009E00198E0000B200
+00B200089A001992000000000000000000000000003A7D00198E0000B20000D70000AE0000D20000
+00000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E6089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896
+000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+00000000000000DF0000BA0000B600009E0000B60000BA0000C600000000000000000000009E0000
+CA00089A00218A00318200298600298600198E00218A003182004A7908218A003182002986001096
+0000DB0000BE0000000000D20000A600009E0000AA00089A0000BE0000C60008960000C600000000
+00000000E30000000000E70000000000C20000BE0000000000000000000000000000000000AE0008
+9A003A7D00109200218E00109200000000198E00298600198E0000AE00009E0000B60000000000D7
+0000AA0000B20000D200109200089A0008960000BE00009E0008960000AE0008960000C600089A00
+08960000A60000B200000000109200109600198E00218E00109200009E00198E00198E00218A0042
+79005A71106B69196B69196369107365194A7508427900089600199200427900000000218A00198E
+00109200109200298A002986000000003A7D00636D106B69197B69197365197B71217B71215A7110
+7B82297B82297B82297B79217B79217B79217B7D217B75217B75213A7D002986003A7D0031820042
+79080000000000004279000000003A7D007365193A7D004279083A7D003182003182002986003182
+003182004279004279003A7D004279084279005275085A7110636D106B6919636D10736519736519
+4279083A7D003182003182003A7D003182002986004279003182003182002986003182003182003A
+7D004A75083A82003A7D003A7D00218A003A7D003A7D00218A002986002986002986003A8200218A
+00218A001992001096002986004A7908000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+218A002986003182003182002986003182004279083A7D003A7D003182003A7D0031820029860029
+86003A820029860000BA0000AA0000C20000AA0000CA00000000000000000000000000218A00218E
+003A7D00198E0000D200089A000000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E6089600089600089600089600089600089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE0896000896000896000896000896005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000E70000D20000B20000DF0000B20000C60000BA0000B6
+0000D200089A00000000009E0000A60000AA0000C60000CE00009E00109200198E00089A0000B600
+00D700089A0000A200089A00089600089A0000000000DF0000BE0000D20000C20000B60010960000
+AE0000DB0000A20000000000D20000BE0000BE0000000000A60010960000000000000000C60000A2
+00009E0000000000000000A20000AA0029860029860042790000000000BE00218E0029860000AE00
+00D700009E0000C60000000000D200009E0000CE0010960000C20000BE00009E0000C200089A0000
+A20000D200089A0000A20000AE0000A60000000000000000B600109200218A00199200198E00198E
+00089A003182004279005A71107B6D217B6D217B69217365196B6919636D105A6D10000000000000
+000000000000000000000000198E002986003A7D002986000000003A7D006B69107B71217365197B
+75217B86297B86297B8629848A297B82297B82297B79217B7D217B79217B71216369105271084279
+084279083A7D003A7D004A7508427D000000000000003A7D004279003182004279084279003A7D00
+4279004279004A79082986003A7D003A7D004279084279004279005A6D105A6D10636D107B651973
+6519636D105A6D10636D105271103A7D005A71104A75084279004279084A75084A75083182003182
+003A7D004279004279084A7908427D003182003A7D003A82003182003A7D004A7508427900298600
+2986002986002986003182003A7D00089600298600318200000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00000000218A003182004A75083182002986003182004279003A7D003182
+00198E00198E00218A00089A002986005271083A7D004A75083A7D00089A00109200218A00000000
+00000000A600000000089A0000AE003A7D000000000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000DF0000BA0000B200198E00
+109600109600218A00089A00198E0000A60000AA0000000000000000000000000000000000E30000
+CE0000CE00009E0000E30000E30000DF0000E30000E30000E30000AA0000000000000000000000DB
+0000D20000E70000CA0000DB0000B20000DB0000000000E30000BA0000000000C20000AE0000B200
+000000009E0000D70000C20000BE00109200000000000000198E003A7D00298A0010960000000000
+BE00318200218A0000A200109200009E0000000000DB0000D20000C600009E0000BE0000C60000C2
+00009E0000CE0000C60000BE0000AE0000AE0000BE00000000000000000000009E0000BE00089A00
+198E00198E00218A000896002986003A7D005A71107365197369197B75217B752173691973651973
+65195271080000003A7D00218A00198E00000000109200000000218A000000000000003A7D004279
+006B69197369197B71217B8629848A298C8E298C8E299492297B82297B79217B7D217B71217B7121
+7B71217B65195A71104A75083182003A7D00318200298600427900000000427D003A7D003182004A
+79084279004279004279084A75083A7D005275083A7D005275084A75083A7D004279005271085A6D
+107365196B6910736519736519636D10736519636D104279005A6D105A6D105A6D105A6D10527108
+5271085A6D10636D105271084279003182002986004A75084279004A75083A7D003A7D0031820052
+71084279083A7D003A7D00318200298600427D00298600218A00198E00298A00318200000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000004A7508318200318200318200318200
+5A71104279084279004A75085271083A7D00218E00009E00199200318200298A005A711052750863
+6D106B6919198E000000005265E60000000000000000000000000000000000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600
+089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+E70000D700218E004279006B69193A7D0010960000AA000000000000000000000000000000000000
+0000000000000000000000E70000E30000E30000DF0000E700000000000000000000000000000000
+00000000E30000000000000000000000000000000000000000000000000000000000E30000000000
+9E00009E00298A0000000000000000AE0000A600109200298600218A0000000000DB0000BE0000B2
+00198E00198E00000000009E0000A20000000000000000000000000000000000DB0000C60000A600
+10920000BE0000CE0000DF00089A00009E0000C60000C20000CE0000CE00000000009E0000A20010
+960000B200089600218A00109200109600198E003A7D003A7D005A71106B69197B6D217B71217B69
+217B71217369195A6D10427D006369100000003A7D00218A00218A000000003A7D00000000000000
+109600298A003182004A75086B69107B71217B75218C8E29949229949629949229949229848A297B
+7D217B7D217B75217B69217365197365197365194A75083A7D004A75083A7D003A7D000000003182
+004279004279003182003A7D003A7D005275085A71105A6D10527108636D104279004A7508427900
+5A7110427900636D106B69196B69107B69197365197365197B71215A6D10736519636D106369107B
+65196B69107365197365195271086369105A6D107365195A6D103182003A7D005275084A75083182
+004A79084279004A75085271085275083A7D003A7D004A75084A79084A79083A7D00298600298600
+2986002986004A7508000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000003A7D003A7D0031
+82004A7508427900427900636D105A6D105A71107365195A6D10636D103A7D00198E0000D200198E
+0010920000AE00198E003A7D0000A200218A004A75080000000000005265E6000000000000000000
+0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000
+00000000000000FFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008
+96000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E600000000000000E70000CE005275087B6D2129860000A600000000000000000000
+00000000000000DF000000005265E65265E65265E600000000000000000000000000E30000000000
+E30019BA4A19BA4A00E30000DF0019BA4A318E9C19BA4A00E30000E3000000000000000000000000
+0000E30000000000000000000029860000C60000000000DB0000B2004A7508298A00218A00218E00
+00000000B20000C60000D200199200089A0000000000D70000000000D20000000000C60000B60000
+B60000B60000DF0000AA0010920000CE0000D20000CE0000CE00089A00089A00009E0000C6000000
+00000000009E0008960000B200009E00109600199200198E00089A00198E002986003A7D007B6519
+6369107B71217B71217B75217B6D217365194A75085A7110000000298A00427D0042790031820000
+0000218A00218A00000000318200218A00218A003A7D006B69197B71217B7D21848A299492299492
+298C8E29949229848A297B79215A71107B7121736519636D105271084279083182003A7D00318200
+318200218A000000004A79084A75084279002986003A7D004279087365196B69107B6D217B65197B
+6D217B65196B69104A75086B69105275085A71107B69197365197365197365196B69107B69217365
+197365196B69197B6D217365197365196B69107365196B6919636D107365195A71105A6D103A7D00
+6B69106369104A75083A7D002986002986006B69194A79084A75084A75085271084A75083A7D003A
+7D003A7D00218A002986002986002986003A7D00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+000000003A7D003A7D00427900318200318200427908527108427D004A7508736519636D107B6D21
+52750829860008960000D70000AE0000BA00009E0000D20031820000000000C60000000000000000
+00000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600089600089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284828442
+4142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE0896000896000896000896005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E600000000000000DB00198E00218A00089A0000
+CE000000005265E65265E65265E60000000000005265E65265E65265E65265E65265E65265E65265
+E600000000000000000000000000000000000000000000000000000000000019BA4A00E700000000
+00000000000000000000000000000000000000CA0000000000C20000C60000000000000000AA0010
+9200089A00218A0000B20000DB0000000000C20000C600089A00109200089A0000000000BE000000
+0000D70000B600009E0000D20000BA0008960000BE0000C60010920000A20000DB0000B20000CA00
+00A60000C60000000000A200089A0000B200009E00009E005A6D10527508318200109200198E0029
+86002986003A7D007365197369197B71217B71217B7121736519636D104279082986000000000896
+003182004A7908318200000000218A00218A00000000218A002986003182003182005A6D10736919
+7B71217B82217B86299492298C8E299C9A297B7D217B79217B71217B71217365197B651973651942
+79082986002986003A8200218A000000004A75084A75083A7D003182003182003A7D007365197B71
+217B79217B71217B6D217365195A6D105271084279005271085A6D107B69197B71217B71217B7521
+7B71217B75217B79217B71217365197365197B6D217B6D217B71217B65197365197B69197B691973
+65195275085271085A6D107B6D217B65194A7508427908318200527508636D10636D107365195271
+084A75084A75084279004279003182003A7D00298600218A00298600298600427900000000000000
+FFFF00FFFF000000000000003182003182003A7D004A75084A79085A71100000000000004A790842
+79003A7D005A71107B71215A6D105A6D105A6D103A7D0000A20000BE0000DF0000E7000000000000
+000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008
+9600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000AA
+0000DB0000CA0000E30000A6000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+00000000000000000000005265E600000000000000E30000DF0000000000DF0000000010920000AA
+0000000008960000AE00009E00198E00198E0000DB0000000000AA0000AA00089A0000D200000000
+00000000E30000B60000000000AA0000BE0000CE0008960000A20000A60000A20000D200089A0000
+B20000A20000BE0000AE00089A0000B20000000000A20000B20000C6004A75084A75087B71217B82
+21736519298600198E003A82003A7D003182006B69196B69197B6D217365197365197365195A6D10
+5A71103182003182000000001096002986006B6919000000198E000000001096002986003A7D0029
+86004A79085271107B69217B79217B82217B8221848A29848A298486297B7D217B75217B71217B6D
+217B69215A7110527108318200218A00218A003182000000004279004A75083182003A7D00427908
+4A75085271087B75217B86297B82217B6D216B69197365194A7508636D107365195A71105A6D1073
+69197B75217B7D217B79217B7D217B79217B7D216B69197B71217B75217365197B71217B71217B71
+217B71217B69217B71216369104A75085A6D106B69197B69197365195A6D10527508527108527108
+5271085A6D10636D104A7508636D10636D104A75086B69104A75083A7D004279084A75083182003A
+7D006B69194279004279000000000000003A7D004A75084279003A7D004279003182000000000000
+00FFFF00FFFF000000000000000896003182005271104279001092003A7D00636910736519427900
+08960000CE000000000000000000005265E65265E60000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E6089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF00
+0000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E60000000000000000000000000000000000000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E60000000000005265E600000000000000000000000000000000E700
+00000000BA0000000000BA0000000000CE00109600089A0000C60000C20000D20000B60000000000
+BA0000B60000000000000000000000BA0000DB0000000000CA0000AA0000DB00009E0008960000A6
+0000BA0000D700089A0000AA0000BA0000B20000BA0000000000000010960000B20000B20000CE00
+4279087B65197B7D218C92297B75212986003182002986004A79083A7D005A6D107365197B69217B
+69217365197B65195A7110427D004A7508199200000000198E00198E00000000089A00218A000000
+000896002986003A7D002986004279085A71107365197B71217B7D217B86298C8E297B82217B8221
+7B79217B75217B6D217365195A7110636910527108298600000000000000000000298A002986004A
+75083182003182003182003A7D007B69197B75217B86297B71216B69197B69217B65195A6D107365
+19736519636910636D107B71217B7D217B82297B7D217B7D217B79217B7D217B7D217B75217B7121
+7B71217B71217B71217B75217B6D217B71217365197365195A71107B69197B71217B71217B712142
+79004A75085271085A6D107B65195A6D106369105A71105271105271085271086369105271084279
+004A75084279005275084A7508636D104A75087365195271085271107365196B69197B6519636D10
+5A7110000000FFFF00FFFF00000000000000FFFF00FFFF0000000000A20000AE0000BE0000C60000
+9E00198E005A71105275083A7D00089A0000B6000896000000000000000000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E6089600089600089600089600089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF00000000
+0000000000000000FFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+0896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E60000000000000000005265E60000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000052
+65E65265E600000000000000000000DF0000DF0000DF0000BE0000D70000BA00009E00089A000000
+0000000000000000000000000000000000000000DF0000CE0000000000000000000000BE0000DB00
+00A20000CE0000C60000B60000A60000CE0000BA0000B20000AE0000000000000000CA0000000031
+820010960000A200109200198E006B69107B69216B69104279001096003A7D004279005271085A71
+107B69217B71217B6D217B7121736519636D105A6D105A7110736519736519318200000000000000
+218A00109600089A00000000089600298600218A004279005271086369105A6D107365197B71217B
+7D217B82217B82217B79217B71217B6D217365196B6919527110427D00427900000000298A003182
+000000002986004A75083182003182004A75084A79085275087B71217B75217B7D21736519636D10
+5275087365196369107365195A6D106B69197B69217B82297B8229848A297B86297B86297B82297B
+7D217B7D217B7D217B75216B69197B75217B71217B71217B6D217B71217365197B69196B69108C92
+297B82217B86297365195A71107365196B69107365197B65197365197365195A7110636D10527108
+5A6D105A6D105275085275085271085271085275087365197B65195A6D107B65195A71107365197B
+6D217B75217365197365195A6D10000000000000000000FFFF00FFFF000000000000000000003A7D
+0000A60000D200009E0000E70000D20000D700009E00298600000000000000000000000000000000
+0000000000005265E65265E60000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E600000000000000000000DF0000E30000000000DF0000000000BA0000BA00
+00CA0000BA0000DF0000000000A20000C60000B60000E70000AE0000000000BE0000000000BE0000
+000000D20010920000B60000AA0000A60000B20000BE0000AE0000BE0000AE000000000000000000
+0000AE0000000000B20000D20000CE0000A600109600198E005A6D10427908218A00298600298600
+4279004A75085271105A6D106B69107B6D217B71216B69197369195271083182003182007365197B
+7121089A00218E00000000218E00109200000000198E00109600318200218A003A7D005A71104279
+084A75087365197B71217B7D217B71217B71217B6D217369197365196B69195271084279084A7508
+000000218E00198E00000000298A002986003182003A7D003182003A7D0042790842790052710863
+69106B6919636910636D105A6D105271085A6D106369107B65197B69197B7D21848A298C8E298C8E
+29848A297B86295A71107B82297B82297B75217B7D217B75217B79217B75216B69197B75217B6D21
+7B69217B71218C8E299C9A298C8E299C96297B69197369197365197365196B69106B69196B69196B
+6910636D107B65196B69197365197B65195A6D107B65197365195A6D10636910636910636D107B69
+216B69197365197B69217B71217B6D217B6D217B7521000000000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF0000000000000019920000C600298600298600089A0000DB0000E70000E30000000000
+00000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600
+089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E600000000000000000000000000000000000000
+E30000E70000000000B60000BE0000C60000B20000000000B20000B20000CA0000E30000AA000000
+0000000000E30000DF0000CA00000000000000000000000000000000000000000000000000000000
+00000000D700089A0000C60000000000C60000DF0000A20000BA003A7D004A75084A75085275084A
+79084279003A7D004A79085271086369107B69197B69196B69197B69217B71217B71216B69194A75
+08298600218A00298600198E00009E00000000218A00218E000000001096003A7D00318200218A00
+2986003A7D003182003A7D005271086B69197B69217369197B6D217365197B71217369196B69195A
+6D10000000000000000000198E003A7D00198E000000002986003182004A79084279083A7D005275
+085271106369107365197365197B6D215A71105A6D106369105271087B65196369107B6D217B7D21
+848A29A59A31A59E31A59E318C8E29848A297B82297B79217B82297B7D217B82297B79217B79217B
+75217B79217B79217B7921848A297B86299C9629A59A31CEC6197B82216B69197365197365197B69
+197B71216B6910636D107365196B6910636D106B69197B6919636D106B69197365197B6921736519
+6B69197B6D217B65197365197365197B69197B69197365197B71217B7D217B7D21000000000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000AE0000B60000C20000BA001096002986
+0000C20000BE000000000000000000005265E60000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008
+96000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+0000000000E70000DF0000000000000000000000C20000CE0000B60000000000000000AA0000BE00
+00D20000C20000000000000000000000E30000E70000000000DF0000B60000D20000E70000E30000
+AA0000BE0000E70000E70000000000000000000000000000C200000000089A0000A60000AE003A7D
+00736519427900636D105A6D107365197B65197365197B75217B71217365197B6D217B6921736519
+7B71216B69195A6D105271083A7D001992001092004A7908298600000000089A00000000218A0019
+8E00218A002986003A7D003A7D00427900427900298600527108527110636D107B65195A6D107365
+19636910736519636D104A7508218A000000003A7D003A7D00198E00000000218A00298600427900
+3A7D002986004279085A6D107365196B69107B6D217B651973651952710852711052711052711073
+65197B69217B7D21949229BDB229C5BA21ADA631A59E319C9A299492297B86297B86297B79217B82
+217B7D217B7D217B7D217B79217B79217B7D217B8629848A29949229949229A59A31A59A317B7521
+7B6D217B69217B6D217B6D217365197B69197B71217365197B69217B6D217B69197B65197B6D217B
+69217B6D217B69197365197B6D217369197365197B69217365197B71217B75217B7D217B75217B79
+217B7521000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000527110298600
+089A00089A0000C20000CE0000AE0000E3000000000000000000000000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600089600089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+000000000000000000000000000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000000000FFFFFFFFFF
+FFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE0896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+0000000000005265E600000000000000DF0000DF0000E30000000000000000E70000CA0000CA0000
+000000C20000D20000C20000CE0000000000000000000000E70000E30000DF0000000000AA000000
+00009E0000BA0000C200000000000000000000000000009E0000B20000B20000A20000A600089600
+00000000B20000A600218A002986007365196B69197B71217B69197B69217B6D217B6D217B75217B
+71217B6D217B6D217365197B69215A6D105275084A7508318200109200109200089A001092000000
+00000000218E00218A00198E003A7D003182005275085275084279004279003A7D004279005A6D10
+3182004279005275083A7D004A75085A71104A75083A7D004A7508000000089A00089A0000000000
+0000298600298A002986004A75083A7D005271086369107365196B6910736519736519636D106369
+105A6D106B69106B69197B6D217B69197B7D21BDB621E6DF10D6CE19D6CA19ADA231CEC619949229
+848A297B82297B82297B86297B86297B86297B82297B82297B79217B82297B86298C8A298C8E299C
+9629848A297B82217B7D217B71217B69197B71217B6D217B69217B6D217B69197B69197B69217365
+197369197365197B6D217B65197B69217B6D217365197369197369197B75217B6D217B75217B7121
+7B7D217B71217B7D217B71217B7D21000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00000000218A0000DB0000BE0000E70000E70000DF0000B60000C2000000000000000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008960008
+9600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000000019BA4A00E30000DF0000E30000DF000000
+0000CA0000E30000E70000000000E30000E30000CA0000000000E30000E30000E30000E30000E300
+00E30000000000000000E30000000000000000000000BA0000CA0010920000AE00009E00009E0000
+9E00198E00089A00000000089600109200109200089A004A75087365197365197365197B71217369
+197369197B71217B79217B71217B75217369197365197365195A6D10427908199200109600009E00
+109600009E00000000000000000000218E00318200218A005A71104A7508736519636D107B71216B
+6910427900427D003A7D003A7D00427900318200427900298600000000000000000000000000089A
+00198E00198E00000000318200218A002986004A7508427908527508736519736519736519527108
+5A6D105271106B6919527108636D10636D107B69197B69217B7D217B8229B5AA29EFEB08EFEB08E6
+E310BDB621A59E319C96298C8E29848A29848A29848A297B82297B86298C92297B79217B82297B82
+297B82219492299492299492297B82217B7D217B75215A71107B75217B75217B6D217B6D217B6919
+7365197365197365197B71217365197369197B6D217B6D217B6D217B6D217B71217B75217B75215A
+71107B71217B75217B69217365196B69197365197365197365197B6D21000000FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF000000004A7508199200218A00089A00427900089A00218A003A7D00109600
+00D7000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000019BA4A00E30000E300
+00E30000DF0000DF0000000000DF0000DF0000000000DF0000CA0000E30000000000DF0000E30000
+DF0019BA4A00E30000E70000000000CA0000B20000DB0000CE0000A200009E0000B60000A60000AE
+00109200109200198E00318200298600318200198E00000000109200089A003A7D005A7110636910
+7B69197B69217B71217B79217B75217B75217B75217B69217B71217365196B6919636D106369106B
+691900BE0000BE0000AE00109600000000000000000000109200298600218A002986003182006B69
+196369107365197B7121636910427908427908318200318200298600198E00218A00218A00000000
+089600109600109600089600109600000000109200198E00298600298600427D0052750842790052
+71085271084279084A75084279004A7508527108636D107365196B69197B69197B75217B75219496
+299C9A29AD9E31BDB229ADA629F7F700A59E319C96299C9A298C8A298C8E298C8E299496297B8629
+7B86297B7D217B86297B86298C8E29848A299492299C96297B86295A71107B79217B71215A71107B
+75217B69217B71217B75217B6D217B71217B6D217B71217B71217B71217B79217B7D217B71217B7D
+217B71217B7D217B71217B71217B6D217B69217B69216B69196B6919636910736519427908527110
+000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000006B69107B69194279003A7D0029860029
+860000AA0000D20000C60000000000DF0000E3000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E6089600089600089600089600089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E600
+000000000000000000000000E30000000000000000000000DB0000000000DF0000DB0000CA000000
+00000000000000318E9C19BA4A00E30000E30000000000E70000BE0000D70000DB0000CA0000B600
+089A0000CE0000D20000CA00109600089A00427D00527108636910427900000000199200198E0010
+96004A75086B69197369197B6D217B71217369197B75217B69217B71217B69217B71217365197365
+196B691952750852711052750800C20000BE0000BE00000000000000000000218A0000BE00109600
+198E002986001096006369105271087365197B6D216369104A7508318200218A0029860010960021
+8A00298600000000109600089A00109600109600089A00000000198E00089600218A00427D002986
+002986003A7D00427908427D004A75083A7D004A7508527108527108636D106B6919636D107B6919
+7B6D217B75215A7110848A29949229A59E31A59A31F7F700DED710A59E31949229DEDB109C96298C
+8E298C8E298C9229848A29848629848A297B82218C8E29848A298C8E298C8E298486297B86297B79
+217B7D217B6D217B6D217B75217B75217365197B71217B71217369197B6D217B75217B79217B7921
+7B6D217B7D217B7D217B7D217B79217B79217365197B71217B69216B69196B69197365195A6D105A
+6D10636910427900218A005A6D10000000000000FFFF00FFFF0000000000000000DB004279083A7D
+0000BA0000B20000B60008960029860010920000BE00000000198E000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284
+424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E600000000000019BA4A00000000E30000000000000000E30000DF00000000000000
+00DF0000CA0000000000000000E300318E9C00000000E30000DF0000000000C20000BA0000E30000
+DB0000C200089A0000B60000AA0000BE0000A20000B20000A600218E005A6D106369107B69193A7D
+00000000218E005271085275087B6D217B71217B71217B69217365197365197365197B69217B6D21
+7B71217369197369196369105A6D10427900318200089A0000B20000BE0000BE0000000000A60000
+B20000AE00109600089A00198E00198E00218A004279083A7D005A6D106369106B69193182002986
+00298600218A003A7D00218A00198E00000000089A001096003A7D00089A00000000089A003A7D00
+199200318200298A003182003182003182004279005271084279004A75083A7D005271085271085A
+6D10636D106369107365197B71217B75217B79218486299C96298C8E29CEC619A59A31A59A31DED7
+109C96298C8E299C96298C8A299C96298C8E29848A298C8E29848A29848A299492298486298C8E29
+848A298C8E297B82217B7D215A71107B7D217B71217B75217B75217B75217B71217B71217B71217B
+75217B75217B6D217B79217B79217B79217B82297B82297B75217B6D217369197B69217369197365
+19636910636D104279084279084279007365193A7D00009E00109200198E00000000000000089A00
+00D20000B6000896006B6919198E0000BA0000DF0010920010920000CA00000000000000089A0000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600
+089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E600000000000000E30000E30000000000000000DF0000
+E30000DF0000000000000000000000000000DF0000000000000000000000DF0000000000DF000000
+0000000000B60000AA0000DB0000C60000AE0000BA0000D70000BA0000A60000AE0000AE00089600
+4A75087365194A7508000000089600198E002986003A7D006B69197365195271085A71106B69196B
+69197B6D217B6D217B6D217369196B69196369107365194279083A7D00218A00089A000896000896
+0000000000C20000A20000AA00198E00089600109600109200089600198E003182004A7508427900
+4279004279003182004A7908298A00218A00218A00218A00198E00199200000000198E0000000000
+0000000000089A00198E00198E002986003A7D003182003A7D002986004279083A7D004279003A7D
+003A7D004279005A7110736519636D107365197B6D217B6D217B79217B6D217B82218C8E299C9629
+949229A59A319C96298C8A298C8E298C8E298C8E299492298C8E299492298C8E29848A299492298C
+8E29848A298C8E298C9229848A29848A297B86297B86297B79217B82297B79217B79217B79217B79
+217B75217B75217B79217B79217B71217B75217B79217B8229848A297B86297B79217B75217B7921
+636D107B65196B69196B69105A71104279083A7D003A7D00198E00427900636D1031820000CA0008
+9A00198E0000B60000CE0000BE0000D20000BE0000AE0000C20000B20000CA0000BA0000B60000CA
+00000000089A0000AE000000000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008
+96005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+0000000000E30000E70000DF0000000000000000E30000E3000000000000005265E6000000000000
+00DF0000C20000000000D70000E70000000000000000AA0000A20000DB0000B60000BE0000AA0000
+A20000BE0000BE00218E003182003182004A75080000003A7D004279005A6D105271084279083182
+003182006369105A6D107365197B6519636D107365197365196B69196B69195A6D105A71104A7908
+318200298600089A0010920000000008960000A60000A60010960010920010960010960029860019
+92004279083182004279084A75083A7D003A7D00089600298600218A003A7D00198E003A7D000000
+00000000000000000000218E00298600089600198E00198E002986001096003A7D003A7D00298600
+4A75085A71104A75083A7D004279004A75085275087365196369107B69197B75217B75217B75217B
+82297B82217B8221848A299496299C9A298C8E29848A29848A297B8221848A29848A29848629848A
+298C8E298C9229848A298486298C8E298C8E29949229848A29848A297B86297B86297B82297B7D21
+7B7D217B7D217B75217B71215A71107B75217B75217B79217B7D217B7D217B79217B82297B862984
+86297B82217B7D217B75217B7D217B71217365197B65195A7110318200218E0000BE0000CA0000A2
+002986004A790800AA00089A00318200089600009E0000C60000A20000CA0000DF0000DF0000AA00
+00CE0000B200009E0000000000000000000000A6000000005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600089600089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE0896000896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E60000000000005265E600000000000000E30000E30000000000000000DF0000000000000052
+65E600000000000000000000000000000000A60000C200009E0000A60000E7000000000000000000
+00000000000000009E0000CE0000A60010920000A600298A00198E000000001992005A71107B6519
+7B71217B65193A7D003A7D00218A003182005271105A7110527110636D105A6D105271105271106B
+69194A75083A7D00298600427900298600218A00109600000000000000009E00009E0000A20000AA
+0010960000B200218A00198E002986003182004279084A7508318200318200198E003A8200199200
+198E00109600199200000000000000198E00298600109600199200198E00198E002986002986003A
+7D003A7D003A7D004A75083182004A75083A7D004279004279004279085A6D106369106B69197B6D
+217B71215A71107B82217B86297B82217B8221848A298486298C8E298C8E297B82218C8E299C9A29
+848A297B8221848A29848A29848A298C8E298C8E298C92298C8E298C92298C8E298486298C8E297B
+82218C8E298C92297B82297B79217B7D217B79217B75217B75217B75217B79217B7D217B75217B79
+217B82297B86297B86297B7D217B79217B75217B6D21636D107B7921736519636D100896003A7D00
+00D20000D20000C200089A0000B20010920000D70000B20008960000AE0000AE0000D20000D70000
+D70000AE0000DF0000BE0000E30000DF000000000000005265E60000000000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008960008
+9600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0824
+6B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08246B08246B
+08246B08246BFFFFFF08246BFFFFFF08246B08246B08246B08246BFFFFFF08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFFFF08246B08246B0824
+6B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246BFFFFFF08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E60000000000000000005265E600000000E70000E3000000000000
+0000000000000000000000000000000000000000D70000E30000000000000000000000D20000CA00
+00DB0000C20000E30000E30000D200089A00000000009E0000BA00009E0008960000BA0029860000
+00003A7D006369107B71216B69196369102986003A7D002986004279004279084279003182004279
+085A6D104A75084A7508089600298600298600198E00198E00198E00218E00298600009E0000A600
+000000089A0000A60000B20000A600109200198E003A7D00298600318200318200298600218A0029
+8600089A00198E00198E003A7D00089A00000000000000218A00218A00089A003A7D00199200198E
+00318200298600218A002986003A7D003182003A7D004A75083A7D00527508427900427908527110
+736519636D105A6D107B6D217B75217B75217B79218486297B82217B8629848A299C9629848A298C
+8E298C8E298486298C8E29848A297B8221848A298C8E29848A298C92298486298C8E298C8E298C8E
+29848A297B8629848A299C96297B82217B82297B86297B82297B7D217B7D217B7D217B6D217B7921
+7B7D217B79217B79217B82299496297B86297B79217B7D217B7D217B6D217B69217B6D2173691973
+65197B6919298600009E0019920000B20000CE0000B60000E70000B20000B60000CE001992002986
+003A7D00089600109200009E0000AA0000DF0000E30000E3000000000000000000000000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84
+8284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08246B08246B08246BFFFFFF08246B08
+246B08246B08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFFFF08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+FFFFFF08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFFFF08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFFFF0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E6000000000000000000
+19BA4A0000000000005265E65265E600000000000000000000CE0000CE0000B20000B600089A0019
+8E0000000000000000000000000000C20000CA0000D20000BA0000DB0000DB0000000000CE0000B2
+0000AE0000A200000000109600218A00318200298600318200318200318200427900198E00298600
+318200318200427D002986003182003A7D00109600109600089A00198E00089A0000C20008960063
+6D106B691929860000A60000000000B20000BE0000A200089600218E00218A00109600298600427D
+00298600318200089600199200198E00089A00089A00218A00000000198E00000000218E00218E00
+1992003A7D00199200218A00198E00298A00218A003A7D002986002986002986003A7D00427D0042
+7D004279084A7508527108636D106B69197B69197B69197B71217B7D217B82297B82217B86297B86
+297B82217B8221949229848A297B82217B82297B82217B82217B82217B8629949229848A29848629
+8C8E29848A29848629848629848A298C8E297B8629848A29848A298486297B86297B82297B82297B
+7D217B7D217B75217B79217B75217B79217B82297B86297B86297B86299496297B75217B79217365
+197B7121636910636D104A75085275083A7D004A750800B20000AE0000E30000E300000000000000
+00E700009E00298600198E00218A0000CE00218A0000B20000AA0000DF0000000000000000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600089600089600089600089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFF
+FF848284848284848284848284848284848284848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000
+0000000000000000000000FFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08246B0824
+6B08246BFFFFFF08246B08246B08246B08246B08246B08246B08246BFFFFFF08246B08246B08246B
+FFFFFF08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246BFFFFFF08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFF
+FF08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246BFFFFFF08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600
+0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E60000000000000000000000000000005265E6000000000000218E0000B200218A0000BE
+00009E00089A003A7D003A7D00089A0000000000B60000000000000000C20000BE0000A20000DF00
+00000000000000B20000A60000D20000CA00000000109200089A00089A000896003A7D00198E0031
+8200318200109200009E00199200218E00198E0000B60008960000BE00198E0000BE00218A001096
+0000A20000C600009E00636D10527508198E00000000009E0000C60000A20000AE00109200298600
+298A00318200298600318200427D00089600198E00089A00218A00089A00089A00000000089A0008
+9A00000000089600198E00089A003A7D00298600109600298600298A003A7D00218A003182003A7D
+00427900427908427D004279004A75084279004A75087365196369107B6D217B71217B75217B7521
+7B7D217B82217B82217B82297B8229848A297B86297B82217B7D217B7D217B7D217B82217B82217B
+82217B82217B8221848A298C8E298C8E29949229949229848A29848A29848A298C8E297B82217B82
+219496297B7D217B82297B7D217B7D217B79217B7D217B79217B7D217B82297B86297B86297B8221
+7B82217B82297B75217B75217365197365195271104A79083A7D005A711008960010920000D20000
+000000000000000000E30000000000000010920000AA0000B60010920000A60000BA0000BE0000DF
+000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142
+FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF08246B08246B08246B
+FFFFFF08246B08246B08246B08246BFFFFFF08246B08246BFFFFFFFFFFFFFFFFFF08246B08246BFF
+FFFF08246BFFFFFF08246BFFFFFFFFFFFF08246BFFFFFF08246B08246BFFFFFFFFFFFFFFFFFF0824
+6B08246B08246BFFFFFFFFFFFFFFFFFF08246B08246BFFFFFF08246B08246B08246B08246BFFFFFF
+08246B08246B08246BFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFF08246B08246BFFFFFFFF
+FFFF08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246B08246BFFFFFFFFFFFFFFFFFF08246B0824
+6BFFFFFFFFFFFF08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E60000000000000000000000000000005265E600000000CA00
+00B600089A0008960000BA00527508427900198E0031820000000000B60000BE0000C600009E0000
+0000000000000000000000009E0000000000AE0000BA0000B60000000000AA00009E0010960000C6
+00109200109200218E0010960010920000BA0000A60000A60000AA0010960010920000A600109600
+00CE00089A00109200009E0000C60000AA0000A6004A7908198E00009E0000000008960010920010
+92001092002986003182003182003A7D00298600298600298600089A00089A00218E00198E00218A
+00000000000000218A000000000000001992003A7D00198E003A7D00198E003A8200298600198E00
+218A00218A002986004A75085A6D104279003A7D005271084A75085275084A75086B69107B712173
+65197369197B7D217B79217B79217B7D217B82217B86297B7D217B86297B82217B82219496297B7D
+217B75215A71108C8E297B82217B82218C8E297B82217B8629848A298C8E29848A29848629848629
+848A29848A297B86297B86297B86297B82297B79215A71107B82297B79217B79217B7D217B75217B
+82299496298486298486299C96297B82297B79217B75217365197B65197B6D214A75081092001092
+00218A0008960000AA00109600009E0000000000000019BA4A00000000AE0010920000CA0000B200
+4A750842790000B6000000000000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600
+089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246BFFFFFF08246B0824
+6B08246BFFFFFF08246BFFFFFF08246BFFFFFF08246BFFFFFF08246B08246BFFFFFF08246BFFFFFF
+08246B08246B08246BFFFFFF08246B08246B08246B08246B08246BFFFFFF08246BFFFFFF08246B08
+246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08246B0824
+6BFFFFFF08246BFFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246B
+08246B08246BFFFFFF08246BFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E60000000000005265E60000005265E652
+65E600000000000000BE0000AA0000BE0000C600218A00298600089A0000BE0000000000000000CA
+0000A20000A600089A0000AE0000AA0000000000AA0000000000000000000000000000000000D200
+00BE0000A200009E0000A600009E00109200089A00218E0000BA0010920000AE0000B20010920000
+A60000AE0000CE0000AA0000CA0000A200089A0000AA0000A60010920000B20000BE0000BE000000
+0000C60000BE00109200089A00089A002986003182003182003A7D00318200427900218A00198E00
+089A00109200009E000000000000000000000000000896003A7D003A7D00089600198E00198E0019
+8E00298600198E00199200198E00218A004A75082986002986005275083182005271084279004279
+084279007365197B69217365197B71217B79217B71217B7D217B82217B7D217B7D217B8221848629
+7B82217B82217B86297B79217B75218486297B82217B7D217B79217B86297B86297B8221848A297B
+8629848A298C8E29848A298C8E297B82218C8E298486297B7D217B82297B7D217B75217B7D217B6D
+217B71217B7D217B75217B82298486297B86297B82217B82217B75217B69217365197365194A7908
+4A750873651942790000C60000A20000A20000D70000BA0000000000000000000000000000000000
+000000D70000AE003A7D00009E0000A200218A000000000000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF848284000000
+000000000000000000000000848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08246B08246B08246B08246B
+08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246BFFFFFF08246BFFFFFF08246B08
+246BFFFFFF08246BFFFFFF08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFF
+FF08246BFFFFFF08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFFFF08246B08246B
+FFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246B08246BFFFFFF08246B08246B08246BFF
+FFFF08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246BFFFFFF08246B08246B08246BFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+005265E65265E65265E65265E600000000000000CA0000E30000BA0000000000BA0000B600089A00
+00000000B60000E700089A00089A00218A00198E0000A20000D20000000000C60000AE0000000000
+000000C60000000000DB0000BA00009E0000AA00218A00198E00009E00089A00218A00109600089A
+00109200009E0029860000A20000C60000D20000BE0000A20000DB0000B60000B20000A20000AA00
+00B20000000000000000000000A600109600109200089A0029860029860029860031820029860031
+8200298600218E00089600089A00089A00089600000000000000089A00109600089A003A7D000896
+00000000000000000000000000198E00109200198E00427900218A00298A00427D00318200318200
+4A75085A71104A79084279005A6D106B69197B6D217B65197B71217B75217B79217B75217B7D217B
+79217B75217B79217B79217B86297B8229848A29848A297B82299496297B75217B79217B75217B7D
+217B79217B86297B82217B82218486297B8221848A297B8221848A297B86299496297B79217B8221
+7B75217B7D217B7D217B71217B75217B7921636D107B7D217B82217B7D217B86297B79217B7D217B
+71215A7110298600318200298600089A00298600198E0000AE0000CE0000E70000DF000000000000
+0000000000000000000000000000DF0000AE0000A60000BE0000D2000000000000000000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600089600089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFF
+FFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08
+246B08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246BFFFF
+FF08246BFFFFFF08246B08246BFFFFFF08246BFFFFFF08246B08246B08246B08246B08246BFFFFFF
+08246B08246B08246BFFFFFF08246BFFFFFF08246B08246B08246B08246BFFFFFF08246B08246B08
+246BFFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246B08246BFFFF
+FF08246B08246B08246BFFFFFF08246BFFFFFF08246B08246B08246B08246B08246BFFFFFF08246B
+08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E600000000E30000000000E30000000000
+E30000BE0000BA0000000000000000000000CE0000D70000000000000000CE0010960000CE000000
+0000A200218A0000000008960019920000000000A20000BA0000C6001096004A79085271103A8200
+089A00109600298A00736519298600198E00198E00009E00009E0000A200009E0000A20000D20000
+DF0000D70000D70000000000000000A20000AE00198E0000B600199200199200218A003A7D004A75
+083A7D004A75083A7D00218A00218A00198E00089A00109200000000000000000000000000199200
+089A00089A00198E00000000000000298600318200089A00089A003A7D00198E003182003A7D0029
+8600427D004A79085275084279005A71105275084A79085271086369107B69217B69217365197B79
+217B75217B79215A71107B7D217B7D217B79217B82217B8221848A29848A299492297B82217B7D21
+7B79217B75217B75217B75217B7D217B7D217B7D217B86297B86297B8221848A297B82217B82217B
+86297B79217B82217B75217B7D217B79217B7D217B71216B69197B69217B6921636D107B75217B7D
+217B79217B79217B79217B71217B6921089A0019920000C60000B20000B60000A200009E0000BA00
+00E30000E30000000000000000000000000000000000000000000000DF0000000000000000000000
+00000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008960008
+9600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482
+84424142FFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000
+0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B0824
+6B08246BFFFFFF08246B08246B08246B08246B08246B08246BFFFFFF08246B08246B08246BFFFFFF
+08246BFFFFFF08246BFFFFFF08246BFFFFFF08246B08246BFFFFFF08246BFFFFFF08246B08246B08
+246BFFFFFF08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246B08246B08246B0824
+6BFFFFFF08246B08246B08246BFFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFF08246B
+FFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFF08246BFFFFFF08246B08246B08246BFF
+FFFF08246BFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFF00
+00000000000000000000D20000BA0000D20010920000000000BE0000000000AA0000A20000C60008
+9A004A79084279083A7D00000000000000000000000000109200198E00198E0000C200009E0000CE
+00009E0000DB0000DB0000DB0000B60000B60000000000AA0000A600009E00109200218A00009E00
+298600218A003182002986004A75083A7D00298600298600198E00198E0008960010960000000008
+9A00000000218A00089A00199200000000000000218A00198E00089A00218A00218E00198E002986
+002986002986003182003A82003182004279083182003182004279004A75084A75085A6D106B6919
+7B6D217365197369197B71217B7D217B75217B75217B75217B7D217B7D217B82297B8221848A298C
+8E29848A297B82217B79217B75217B75217B71217B79217B79217B79217B82217B86297B79217B86
+298486298C8E297B82217B86297B7D217B79217B75217B7D215A71107B71217365197369196B6919
+7B69217B71217B75217B7521636D107365197B69217B69216B691931820029860000A20000A20000
+D700089A0000D20000E30000E30000DF000000000000000000000000000000000000000000000000
+00000000000000000000089A000000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF84828484828484828484828484
+8284848284848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF08246B08246B08246BFFFFFF08246B08246B08246B08246B08246B08246B08246BFF
+FFFFFFFFFFFFFFFF08246B08246BFFFFFF08246BFFFFFF08246B08246BFFFFFF08246BFFFFFF0824
+6B08246BFFFFFFFFFFFFFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246BFFFFFF
+08246B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246BFFFFFFFF
+FFFFFFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF08246B0824
+6BFFFFFFFFFFFFFFFFFF08246B08246BFFFFFF08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6000000000000000000000000318E9C0000000000005265E6000000000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000B600198E00089A0000000000C6000000000000
+0000C60000BA0000B20000A60000000000000000000000000008960000B600000000000000218A00
+10960000AA00089600009E00089A0000A20000D70000A20000B20000000000DB00009E0000CE0000
+9E0000A600218A003182002986003A7D002986004A75083182003A82002986002986003A7D00198E
+00089600000000089600000000218A00109600109200198E00000000218A00199200109200218A00
+089600109600198E003A7D003182003182003A7D003182003A7D004279003A7D003182003182003A
+7D00636D107365197B6D217B69197B69217B69216B69197B7121636D107B79217B7921636D107B7D
+215A71107B8629848A298C8A298C8E297B79217369197B6D217369197B6D21636D107B79217B7921
+7B7D217B79217B7D217B82217B82217B82297B82217B86297B86297B82297B7D217B79217B71217B
+75217B6D217365197B69217B71217B6D217B75217B71217B7521736519736519736519636D105A71
+103A7D003A7D0029860000D70000E70000CA0000DF0000DF000000000000000000000000005265E6
+0000005265E60000000000005265E65265E60000000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600089600089600089600089600D6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E60000000000000000000000000000000000000000005265
+E6000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000198E00298600
+3A7D0000000000D20000000000AE0000C200000000000000218A00009E003182000896003A7D0010
+92001092003A7D0000000000A200009E00218A0000CE0000D20000C60000D70000D20000000000D7
+0000CE0000A60010920000A20000A600109600089A002986002986003A7D00427900298600298600
+298A00218A00109600089A00000000000000000000109200089A00198E0000000000000010920019
+8E00198E00218E00089A001096003A7D003182001096002986004279003182003182004279002986
+00218A00218A004A75084279005A6D107365196B69197B69217369197B69217365197B75217B7121
+7B71217B79217B71217B75217B7D217B79218C8E297B82217B75217B6D2173691973651973651973
+65197365197365197B75217B71217B79215A71107B7D217B82217B86297B82217B82217B86297B86
+297B7D217B86297B86297B75217365197365197365196369107365197B69217B6D217B71217B6921
+7365196B69197B65196B69194279003A7D00218A0000DB0000AE0000CA0000E30000000000000000
+00000000000000000000005265E65265E60000000000000000000000000000000000000000005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600D6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6
+D2CE0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000000000E30000BE00109200
+0000000000005265E6000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF00000000000000318200000000198E0019920000000000000000000000AA0000A6000896001092
+005271084A7508198E0000A200198E00089A0000AA0000000000000000000000BE0000CE0000B200
+00CE0000B60000000000AA0000A20000AA0000A60000B200089A00198E003A7D00198E00198E0031
+82002986002986002986002986003A7D00198E0000000000C200000000218A00198E002986000000
+00000000009E00198E00298600109600218A00109600298600198E00198E00218A00109600298600
+2986003A7D003A7D00218A003182002986003182004279005275087365197365196B69197B692173
+65197365197365197B6D217B71217B71217B79217B75217B7D217B75217B7D217B71217B71217B6D
+217B6D217B69217B69217B69217B71217B69217B71217B71217B6D217B71215A71107B79217B8221
+848A29848A29848A29848A298C92297B79217B79217B69216369107365195271104A75085A6D1063
+6D105A6D104279085A6D106B69197B71216B69105A6D103A7D003A7D00009E0000B20000DF000000
+000000000000000000000000000000000000000000000000000000000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600
+089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442
+4142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+DF0000CE0000C2000000000000005265E6000000000000000000000000FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF00FFFF0000000000000000000000000000A60029860000000010920000BE00
+00AE00089A00198E00218E00218A00298600089A003A7D0010920000C20000A20000DF0010960000
+000000000000C20000D70000CE0000000000AE0000A20000C60008960010920000A200089600198E
+00089A00198E002986003A7D003A7D00198E00089A00298600199200000000000000089600000000
+3A7D00198E00000000109600109600218A00198E00218A00218A00218A00298600298600198E0021
+8A00218A00298600298600218A003A82002986003182003A7D00298A003182005A71105271085A6D
+107365197369197365197B6D217B69217B6D217B6D217365197B6D217B7521636D107B79217B8229
+7B6D217365197B69217365197365197B69217B69217B69217B69217B69197B6D217369197B71215A
+71107B75217B7D217B7D21848A298C8E298C8E299C9A297B7D217B7521636D105A6D103A7D003A7D
+004279004279083A7D005A711029860000BE00009E00218E004279087365194A7508218A00009E00
+00D70000D20000000000E3000000000000000000000000005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B0824
+6B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B
+08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08
+246B08246B08246B08246B08246B08246B08246B08246B08246B08246B08246BFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E60000000000000000000000000000000000005265E600000000CA0000B60000A20000CA00
+000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000218A003A7D0000000000000000000000
+B20000000000C20000DB00109200298600298600298600218A00218A00218E0000C20000CA0000CA
+0000D70000DB0000CE0000000000BE0000000000C20008960000000000B20000C60000C20000C600
+00B200298A00199200198E00198E00218A0029860031820031820019920019920019920000000000
+00000896000000001096003A7D0000000000A600109200089A00298600198E00218E00218A00298A
+00198E00298600198E00198E00318200318200298600318200318200218A00298600298600298600
+3182004A7508636D105A71105A6D107365197B69197365197B69217365197B6D217B6D217B71217B
+71217B79219496297B6D217B69216369106369106B69107B65195A6D10636910636D107369197B69
+217B69217B69217B71217B6D215A71107B7D217B7D217B82217B82217B75217B71217365197B6D21
+5271105271104279002986003182004A79083182006B69105A7110198E00218A0000D70000C60010
+960029860000C20000C60000BE000000000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600089600D6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896
+000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+D20000B20000D700009E00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000009E0000AE
+0000DB0000C60000000000000000BE0000D20000BE00218A00218A00089600198E00109200298600
+218A0000AA0000D70000D20000000000000000000000E70000AA0000000000000000000000BE0000
+CE0008960000C200109600009E0000BA00109600198E00198E00298600218A00218A00089A00198E
+00218A00000000198E0000BE00000000427900089A0000000000AA0000A600218A00199200427900
+218A00218E002986003A7D00089A00089A00199200198E00218A00218A002986003A7D0029860021
+8A00298A002986003182004A7908318200427D005A6D105A71107B65196B69197365196369107B71
+217B65197B69217365197B75217B75217B71217B69217365196B69197369195A6D10527110527108
+7365197365195A6D107365196B69197B71217B69217B71217B75217B79217B82217B82217B75217B
+6D217369196B69196B6919636D102986003A7D00218A002986004A75085A71105A71107B6D215A71
+10109600198E0000BA0000CA0019920000BA0000CA000000000000000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E608960008960008960008960008
+9600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482844241
+42FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E600000000000000C60000D20029860029860000AA00198E00000000000000FFFF00FFFF00000000
+00000000D20000000000AE0000000000000000CA0000D700089A0000A200198E0010920029860010
+9600089A0000C600198E0000CE0000DB0000C60000000000000000BE0000000000000000BE000000
+0000000000A20000A20010960008960000C60000A60000A20000B200298600199200218E00109600
+218A0000BA0008960000BA00198E00000000089600009E00000000009E0000D20000000000CE0000
+B200089600089600218A00218A00218E00218A00218E00109600198E00199200218A00218A002986
+00298600198E00198E00199200318200318200427900318200218A003182005275087365195A6D10
+7365196B69106369107365197B69216B69197369197B6921736519736519636D107B651973691963
+6D10636D10636D105271085A71105271085A6D106369107365197B69217365197B6D217B79217B7D
+217B7D217B7D217B7D217B71216369106369104A7508527110427D003A7D00298600318200298600
+298600636D107B69214A7908198E00318200089A0000DF0000E30000000000000000000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E600000000000000C600218A00109200298600427900198E00198E0021
+8A0000000000000000000000000000000000000000000000000000AA0000000000000000DB0000B2
+0000B600298A00109200298600089A0000000000000000A20000000000000000E70000E70000BE00
+00BE0000000000BA0000CA0000000000CE0000DB0000A200089A00109200198E00198E0000B20019
+8E00218A0000BE00218A00198E00089A00089A00000000000000218A0000DB000000000000000000
+0000000000000000CE0000B200089A00218A00218A00218A00218E00089A00198E00199200218A00
+089A00298600198E00218A002986003A7D00198E004A75085A6D103A7D003A7D0029860042790829
+86003A7D004A7508736519636910636D10736519736919636910636D106369106369106B69196369
+105A6D104279003A7D005A71107365195A71104A75084A75085275084A75085271085A6D10736519
+7B71217B6D217B75217B75217B79217B7521636D10736919636D105A71105A6D104A750842790831
+8200218A00218A00198E00198E0029860052710842790019920000DB0000C20000E3000000000000
+000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000FF
+FFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6000000000000000000000000089600218A00198E
+003A7D0000BE0000D70000B200089A0000DB0000A20000B600089A0000DB0000000000AA0000AA00
+00AA0000000000000000D20000CE0000CE0000D200089A0000000000BE0000BE0000000000000000
+BE0000D20000BE0000BA0000000000B60000AA0000CA0000000000BA00009E0000B200009E0000A2
+00089A00009E00109600089600089A00109600089A00089600009E0000A60000000000CE0000B600
+00000000000000000000AA0000A60000AA0000DF00089A00218E00199200218A00218A0029860029
+86003182003A7D00089A00199200199200198E00427900198E001092002986003A7D004A75083A7D
+003182002986002986002986003182003182004279005A6D105A6D107365195A6D10736519636910
+4A75087365197365195A6D103A7D00318200089A001992005271083182005271084A750842790852
+75084A79085271086369107365197369197B71217B7D215A71107B82297B75217B71217B75216369
+106369105A71103182003A7D00198E00198E00218E00318200218A0052710800B20000C2003A7D00
+0000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600D6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08
+96000896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000
+00000000000000000000C20000C20000A60000D20000DB0000000000000000000000000000000000
+000000000000AA0000AA0000C60000000000000000000000000000000000000000000000000000E3
+0000E30000BE0000BE0000E30000E70000BA0000000000000000BE0000BA00089A0000000000A600
+00A60000C60000CA00089A0010960000BA00198E0010960000AA0000A60000A60000B60000D20000
+000000A20000DB0000000000000000A60000AA0000C20000A60000A600089A00009E00218A00218A
+00198E00089A00218E003A7D003A7D00199200109600109600109200298600298600198E00318200
+427900527108527508298600427D00198E00198E00198E00199200198E004279004279005271105A
+7110636D105A71105A6D104279005A6D103A7D004A75083182003A7D00198E00218A00218A002986
+004279084A75084279003A7D003A7D005271106B69197365197B69216B69197B7D217B75217B7921
+7B7D217B75217B7121736519636D10427908298A00218A0000A200009E0000A20010920000AE0042
+79001992000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600
+089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284
+8284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000000000000000DB0000000000000000000000C6
+0000AE0000000000000000000000AA0000AA0000AE0000A60000000000CA0000D70000B20000B600
+00CE00089A0000000000C20000E30000CA0000BA0000BE0000CA0000000000000000C20000E30000
+BA0000000000B20000BE0000D70000A20000BE0000B200218E0000D20000D20000C20000AE0000B6
+0000A20000000000000000B60019920000000000000000DB0000AA0000A60000A20000C60000A200
+00AA00199200199200198E00198E00109200218A00218A00198E00198E00198E00109200089A0019
+9200089A003182004279083182004A7508298600218A00298600109600198E003A7D00199200218A
+004279005275085A71105271086369105271084A7508318200318200298600298600298600298600
+427D002986003182003A7D003182004279002986003182003182005A71107365196B69197B692173
+65197B75217B75217B79217B7921636D107B6D215A6D10636D103A7D0010960010920000AE0000D2
+0000C20000AE0000D20000B600009E0000E3000000000000005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E600000000000000000000000000000000000000000000DF00000000
+00000000D70000DF0000000000000000A20000AA0000000000AE0000AA0000AA0000AA0000000000
+CA0000B60000D70000AE0000D700009E0000000000BA0000CA0000CE0000BE0000BA000000000000
+0000CA0000BE0000D20000000000000000C200089A0000B20000B200089A0000AE0010960000D200
+00BA0000B60000D200009E0000000000C60000CE0000D700089A0000000000C60000A20000B20000
+C60000A60000AA0000AA0000A600218A00109600198E00218E00218A000896000896003A7D003A7D
+00198E00199200199200198E003A7D00318200318200427D00427D00318200318200089A003A7D00
+198E00298600198E00198E002986004279004A75085A71105271104A750831820029860029860029
+86003A7D00298600198E00198E003A7D003A7D002986003A7D002986003182003A7D003182006369
+107B71216B69197B71217365197B69217365197369197B75217B7921736919636910527110298600
+089A0010920000BA00009E0000BA00009E0000CE0000C60000DB000000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000000000
+FFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E600000000000000000000000000000000000000000000
+D70000BE0000C20000D200109600009E0000000000AA0000DB0019920000AE0000000000000000AA
+0000AE0000AA0000000000C60000A200009E0000AE0000DB0000D700089A0000000000CA0000D200
+00CE0000000000CA0000000000000000000000000000000000000000BA0000BE0010960000B20008
+9A0000CE0000AA0000B60000CA0000000000000000000000B20000D70000000000000000000000BE
+0000B60000B20000D200089600009E00089600089A00089A0000BA00009E00089A00089A00000000
+000000298600198E00089A00218A00298600089A00198E00318200218A002986003A7D0029860031
+8200089A003A7D00198E00198E00218A001992003A7D00198E003182004279004279003A7D004A75
+08318200298A003A7D00636D105275083A7D00427908218A00109600198E003A7D00318200218A00
+218A00198E00218A0073651900AE0000CA003A7D00009E006B69195A6D107B69217B79217B82217B
+86297B7521527108298600089A0000CE0000AA0000A20000CA0010920000D20000D70000CA000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FF
+FFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000E3
+0000000000000000000000AE0000C20000C60000AA00089A0000000000BA0000BA0000D20000DF00
+00DB0000D20000000000000000AA0000AA0000AA0000000000D20000CE0000A20000DF00009E0000
+9E0000000000D20000C20000000000000000E30000CA0000CA0000CA0000D20000D20000000000CE
+0000A20000A200109200009E0000AE0000DB0000B60000000000B20000B20000B60000C60000D700
+00000000A200009E0010960000B20000AA00009E0000C60010920010960000BE00089A0000BE0019
+8E00000000000000000000000000198E00218A00089A00298600218A00089A003A7D003182002986
+003A7D00298600298600218A003A7D00089A00109200298600218A00198E00089A00198E00199200
+218A00298600427900427900089600218A005271084279003A7D00218A00218A0000BE0000B60019
+8E00198E00089A00218A001992004279004A7508427900318200218A0000A2003A7D000896002986
+005271107B71219496298C92297B82297B7521527508318200009E0000D20000CA00009E00089600
+00D70000A6000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF000000FFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+00000000000000000000000000000000000000B60000DB0000BA0000C20000000000000000AA0000
+A20000D70000B20000AA0000CE0000D70000000000000000DB0010960000AA0000000000B60000DB
+0000B60000DB0000CE0000D70000000000000000000000E70000CA0000000000CA0000CA0000E700
+00BA00009E0000000000B600089A0000AE0000C20000C20000CE0000C60000000000BA0000AE0000
+CE00009E0000000000000000AA00109200218A0010920010920000A60000A60000B20010960000C2
+00109200000000000000000000218A00089600199200218E00218E003A8200218A00089600298600
+3182001992003A7D00427900298600298600089600198E001096001096003A7D00318200218A0019
+9200198E00089A00198E00199200218A00218A003A7D001992001992003A7D004279004279083182
+0010960000DB00198E0029860010920000BE0000BE0000A600009E003A7D00218E0000DB0000CA00
+3A7D0010920000AE004279007365197B8229CEC6199492297B7D217B7D212986003A7D00089A0000
+E30000DF0000C60000C2000000000000000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E600000000000000000000000000000000CA000000000000000000000000000000
+0000000000C60000B20000DF0000BE0000C60000AA0000B20000000000AE0000B60000C600089600
+00BA0000000000AE0000BE00009E0000D20000C60000D70000000000D20000E70000E70000000000
+E30000CA0000DB0000E70000BE0000BA0000000000B60000CE0000D70000AA0000CE000000000000
+0000C200089A0000D70000DB0000000000000000000000A20000CE0019920008960000A200009E00
+109200089A00218A00198E00218E00000000218A00089600218E00198E00109600109600218A003A
+7D00318200218A00198E00298600318200318200298600199200318200089600218A00198E001992
+003A7D00000000109200298A00218A000896003A7D00298600218A00198E00089A00318200109200
+1096003A7D005A6D1031820010920000BE0000A200198E0010960000B20000A60000A20000D20000
+BE0000C20000AE0000CE0000A60000CE001992004A75083A7D007B71217B8229CECA19848A297B79
+2131820000AE0000D70000DF0000E7000000000000000000005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000
+00000000000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFF00000000
+0000000000000000000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008
+96005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E60000000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E600000000000000000000000000000000BE00
+00BE0010960000000000D70000D70000B600089600089A0000A20000DB0000A2003A7D0000000000
+CE0000D70000D20000D70000BA0000000000AA00009E0000C60000D70000BE0000000000E70000D2
+0000CA00000000089A0000E70000BA0000BA0000C20000E30000000000000000AE00089A0000C600
+00AE0000000000D700089600009E00089A00199200089A0000000000DB0000B20000000000000000
+000000000000000000B600318200198E00218A004A75083A7D00000000089A00089A00089A000896
+00198E00218A004279083A7D001096003A7D00198E00198E00318200298600427900089A00198E00
+198E00318200089600089600000000218A00218E00089A00218A00198E003A7D00198E0008960010
+960029860029860000A200198E00218A00427908298600089A00009E0000A20000AA0000C20000C6
+0000C60000B60000CE0000D70000DF0000BA0000BA0000B600009E00198E0000A600009E006B6919
+848A29D6CA19DED7106B6919318200089A0000CA0000C20000000000E3000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442414284828442
+4142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E60000000000000000000000005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+000000000000D70000C200009E0000BE0000DB0000000000000000000000000000000000C60000C6
+00009E00089A00000000009E0000C60000BA0000BA0000C20000DF0000000000CA0000BA00000000
+00000000E70000E30000D20000E30000000000CE0000CA0000E70000CA0000CA0000D20000DB0000
+000000000000000000000000000000000000000000C60000D70000C20000D70000000000D70000D2
+0000BA0000AA00089A000896002986003A7D00000000000000000000000000000000000000109600
+198E00109600199200218E001096003A7D003A7D00218E00298600427908198E0029860031820021
+8A003A7D00089600298600089A00109600198E00000000318200218A00218E00109200198E00218A
+00089A00089A0000A600218A00109200218A00198E0000BE0000BA0010960042790010920000AA00
+00AE0000CA0000AA0000BA0000BE0000B20000A20000B20000D70000BE0000BE0000E30000E70000
+DB00218E004279007B71218C8E29FFF700B5AE297B7521736519198E0000A6000000000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000
+E3000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+0000000000000000E30000000000BE0000A600009E0000D70000C600109200089A0000C20000A200
+00000000B60000000000B20000000000000000AE0000AA0000A60000AA0000CA0000E30000E30000
+000000CA0000000000C20000CA0000D20000D20000CA0000DF0000000000000000CA0000CA000000
+0000000000000000000000000000A60000000000000000000000000000CA0000CA00089A00000000
+00000000C20000AE00009E0000A60000AE003A7D00427D002986003A7D0029860000000000000010
+9600218A00000000000000000000000000000000218A00198E00109600198E00198E003A7D003182
+00318200427908298600198E004A750829860000BE00199200218E00000000000000218E00198E00
+10920010960010960000BA0000A20008960000A200198E00199200198E00198E00009E0000A20000
+AE00218A0019920000D20000AA0000BA0000D70000B600089A0000BE0000C60010960000BE000000
+0000000000000000BE0000000000AA0000C6005A6D107B7D21CEC6198C8A29736519636D10218E00
+00C2000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E600000000000000DF000000000000005265E65265E65265E65265E65265E6000000000000
+00000000000000000000000000DF0000DF0000000000D200000000000000009E0000D70000DB0000
+AA0000A20000B60000000000D20000C20000000000000000B60000D20000CE0000C60000A20000BE
+00089A0000BE0000E30000000000000000CA0000CA0000CA0000E30000E70000CE0000E70000E700
+00CE0000000000000000CA0000CE0000CE0000E70000D20000D20000000000BA0000A60000000000
+9E00009E00000000089A0000BA00089A0000B200218E00198E003A7D005271082986003A7D003A7D
+005A7110318200298A00318200199200218A000000003A7D00000000199200199200109600198E00
+089600198E003A7D003A7D003A7D003A7D0029860031820010960000BE00009E00089A0000BA0021
+8A0008960010960000B600009E00109200198E0000A600089A00009E0010960000AE001992003A7D
+0010960000B60000DB00009E0000AE0019920000D20000E70000BA0000BE0000BE0000AA0000AA00
+00BA0000000000000000E30000D20000BA0000BA0000000000000000DB004A75087B65197B79217B
+71216B691900BE0010920000D2000000000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E600000000E30000E30000E7000000005265E65265E65265E600
+000000000000000000000000DF0000000000DF0000E30000B60000E70000AE0000E70000CA000896
+0000DB0000B60000DF0000B20000B200218E0010960000C60000A200009E0000AA00000000000000
+00000000D20000BE0000D20000B600089A0000000000000000DF0000E30000E70000CA0000CA0000
+E70000C20000E70000E70000000000E70000CA0000E30000C20000BA0000D20000B60000D2000000
+0000BE0000BA0000BA0000000000000000CA0000B60000BE0000AE00089A005275087365196B6910
+4A75082986004A7508298600636D104279004A79085271087365195A6D1052711031820029860008
+9A00000000000000000000298600199200000000298A003A7D00318200298600089A001092001092
+00009E0010920000BA00000000109600089600109600218A00089A0000A60000B20000B20000B200
+00CE00009E00009E00218A0010920000C60000AE0000AA0000000000000000000000000000000000
+BE0000BA0000E30000000000000000D20000E30000BA0000BA0000E30000CE0000BA0000D2000000
+0000BE004A75085A6D10636D103A7D0000CE0000C6000000000000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E600000000000000E30000DF0000E7000000
+000000005265E65265E600000000000000000000000000C60000CE0000BE0000C20000BE0000C600
+00000000AA0000B60000CA0000C20000D700109600009E0000BE00009E0000AA0000BA0000D70000
+DB0000B20000C60000DB0000DB0000000000000000C200089A0000A60000A20000E70000DF0000E3
+0000DF0000E30000E30000CA00089A0000E70000000000E70000E70000E30000D20000B60000BE00
+00AA0000000000000000E70000BE0000BA0000000000000000000000C20000C60000A20000B60031
+82007B6D217365194279003182002986004279005271085275083A7D007365194279005A6D10636D
+10636D10427900427900318200218A004A7508198E00000000000000000000000000000000298600
+198E0000B20010920000A20000A20000B20010920000BA0000000000B20010920019920029860000
+A20000BA0000A20000DB0000AA0000D70000CE0000DF0010960000000000000000000000DF0000DF
+0000E70000CA0000CA0000000000000000000000E30000CA0000CA0000E70000CE0000000000CA00
+00E30000DF0000E700000000089A0010920029860031820000DB0000000000000000000000000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000E700
+00DF0000E30000000000000000000000000000000000000000E30000DF0000C20000AA0000A60000
+BA0010920000CA0000C600000000009E0000CA00009E0000AE0000A200089600089A00089A001092
+0000CE0000DB0000000000CA0000B20000BE0000D70000000019BA4A19BA4A00000000BA00109600
+00000000DF0000E30000E30000E30000E30000DF0000DF0000000000000000E70000E70000AA0000
+E30000E70010920000E70000000000000000D20000E70000BE0000AA0000AA0000000000000000D2
+0000B20000B200218A003182003182003182004A75083A7D005271083A7D005A7110427908318200
+4279005275085271084279085271085A7110298600318200318200318200298600318200218A0042
+790029860000000008960010920000BE0008960000A20000A60000C20000A20000BA001092000000
+00109600109200218A0000BA0000A600198E0000C20000C60000D70000C200089A0000000000DF00
+00DF0000DF0000DF0000DF0000DF0000E70000E70000E70000E70000E30000E30000E70000E70000
+E70000000000000000000000DF0000E30000DF00000000000000000000009E0000A20000000000E3
+000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E600000000000000000000E30000E30000E30000E30000000019BA4A00DF0000E7
+0000CA0000DB0000D20008960000AE00009E0000AE0000000000A600109200089A0010960000A600
+109600298600218A0000BE0000AA0000C60000000000000000000000BE0000000000E30000E30000
+E30000DF0000000000000000E30000DF0000E30000DF0000000000000000000000000000000000E7
+0000DB0000E70008960000BE0000E70000BE0000B60000000000BE0000B60000B60000D20000E300
+00A60000000000C20000B60000B600109600198E00198E003A7D003A7D0042790073651952711042
+79004A75084279083A7D004A75085271085271087B65195A71105271085271082986003182005275
+08636D103A7D005A71103A7D0000000000000000000010960000AA0000C60000C60000C60000CE00
+00B20000A60000AA00000000198E00089600298A00318200198E0000AE00009E0000DB00089A0000
+B60000CA0000000000DF0000DF0000DF0000E30000E30000E30000DB0000DF0000DF0000E30000DF
+0000DF0000000000DF0000DF0000000000000000000000000000DF0000DF0000DF0000E300000000
+00000000000000E3000000000000005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E600000000000000E70000DF0000DF0000DF0000E300
+00000000DF0000DF0000BE00089A00089A0000CE0000D70000A20000D200000000009E0000C60000
+B200009E00218A0000C200009E0000A20000A60000BA0000B600000000000000FFFF00FFFF000000
+0000000000000000000000000000000000000000000000000000000000000000000000000000DF00
+00D20000CA0000000000E70000E30000BA0000AA0000D20000CA0000BA0000BA0000000000E70000
+E70000C20000AA0000DF0000CA00000000009E0000C600089A0000A20000BA00218A003A7D005275
+08636D105275083182003182003A7D003182005271084279085A71107365195A6D106B6919527110
+3A7D004A75084279004A75083A7D00427908318200318200000000198E0000B20000000000B20000
+A20000BE00089A0000CE0000AE0000A200009E0000000000000000B60008960031820010960000BE
+0000A60000AE0000BA0000BA0000000000000000E70000E30000E30000DF0000E30000DF0000DF00
+00DF0000DF0000DF0000DF0000000000000000000000000000000000000000000000000000000000
+DF0000DF0000E30000E70000DF000000000000000000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000E30000DF0000
+DF0000CA0000E70000000000000000E70000E30000C20000B60000CA0000C20000D70000D7000000
+00009E0000D70000A60000A200009E00009E0000AA0000000000000000DF0000C600000000FFFF00
+FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000E30000000000E70000000000E70000000000
+DF0000E70000000000BE0000BE0000000000000000000000000000E70000BA000000000000000000
+0000000000C20000BA0000E70000BA0000A60000D70000000000DB0000D70000DB0000B60000C200
+1096000896002986003182003182003A7D003182003A7D000000000000000000000000003A7D003A
+7D005275085A6D105271085271086369107365195271083A7D00198E00198E00109600089A000000
+00009E00000000009E0008960008960000B20000AE0010960008960000D20000000010920000A600
+19920029860000AA0000AA0000A20000B60000A60000000000E70000E30000DF0000DF0000DF0000
+E30000DF0000DF0000DF0000DF0000DF0000DF0000DF000000000000000000000000000000000000
+0000000000000000000000DF0000E70000E3000000000000000000000000005265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000
+000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000FFFF
+00FFFF0000000000000000E700000000000000FFFF00FFFF0000000000000000A200009E0000D700
+00C20000CE0000D700000000089A0000AE0000A20000CE0000AA00000000000000FFFF00FFFF0000
+0000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000E30019BA4A0000
+0000E70000E70000E70000000000DF0000E30000000000DF0000000000DF0000DF00000000000000
+00000000D20000D20000E70000C20000B60000E30000E70000BA0000BE0000000000D20000C60000
+DB0000B20000AA0000A20000BA001992003A7D00298600298600298A002986003182000000002986
+004A79080000000000000000004279087365197365194A7508636D10736519427900198E00298600
+318200218E00000000218A00089A00089A0000000000AA0000DB00009E00089A0000B20010960000
+0000000000009E0000C200089A0000AA0000A20000C60000B20000000000000000000000E30000DF
+0000E30000E70000E30000E30000E30000DF0000E30000DF0000DF0000DF0000E30000E300000000
+00000000000000000000000000000000000000000000000000E3000000000000005265E65265E600
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFF
+FFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFF000000
+FFFFFFFFFFFF000000000000000000FFFFFFFFFFFF000000FFFFFF000000000000FFFFFFFFFFFFFF
+FFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF0000000000
+00000000FFFFFF000000000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF
+000000000000000000000000FFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FF
+FF0000000000DB0000D70000CA0008960000000000000000C20000D70000D700000000000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+00000000E30000000019BA4A00E30019BA4A00E30000000000E30000E70000000000000000000000
+E30000E70000E30000000000000000CE0000CA0000E70000BA0000BA0000E70000BA000000000000
+0008960000BA0000BE00089A0000D70000CA0000A20000000000000000B600218A00009E003A7D00
+000000000000298600318200298600089A00000000000000218A00218A006369103182005A711052
+7108318200198E003A7D004A7908298600000000089A00089A00009E0000000000B20000AE0000AE
+00009E0000BA00089A0000CE0000000000DB0000C60000D70000A20000D200000000000000000000
+00DF0000DF0000DF0000E30000DF0000E30000E30000E30000DF0000DF0000DF0000DF0000E30000
+E30000DF000000000000000000000000000000000000000000000000000000000000000000000000
+005265E65265E60000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284
+424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000000000FFFF
+FFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF0000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF
+00FFFF00FFFF00FFFF00FFFF00000000000000000000000000000000000000000000000000000000
+00000000DF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF0000000000000000000000E30019BA4A00E30019BA4A00000000E30000E7
+0000E300000000000000318E9C00E30000DF0000000000000000000000DF0000E30000DF0000CA00
+00000000000000AA0000BE0000C20000D200089A0000B60000D70000CA0000AA0000000010920000
+00000000000000000000002986002986002986003A7D00198E00089A00109600000000218E002986
+00298600218A002986002986003A7D003A7D002986003A7D0029860000000010920000A200000000
+00D20000B60000AA0000AE0000AE00089A0000AA0000A20000000000D70000CE0000B60000AE0000
+CA0000000000E70000E70000E30000DF0000DF0000DF0000E70019BA4A318E9C19BA4A00E30000E3
+0000E30000000019BA4A19BA4A00E30000000000000000000000000000E300000000000000000000
+0000005265E60000000000000000000000000000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF848284FFFF
+FF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFF848284FFFFFFFFFFFFFFFFFF000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000000000000000000000000000FFFFFF000000FFFFFFFFFFFF000000000000000000000000
+FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFF
+FFFFFFFF000000000000000000000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000
+000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000E70000000000000000
+D20000BA00000000000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+00000000FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E600000000000000E300318E9C
+00E30000000000E30000E70000E30000E30000000000000000000000000000E30000E30000DF0000
+000000E30000000000000000CA0000C60000E70000BA0000DB0000DF0000C60000B60000D7000000
+0000000000D700109200298600218A00318200318200089600218A00318200218A00218A00198E00
+089A00218A000000000000003A7D00089A00198E00218A00089A00198E0000000000000000000010
+920000BA0000CE0000000000BA0000B60000BE0000BA0000BA00009E0000A200009E0000D2000000
+0000AE0000D70000AA0000000000000000000000E30000DF0000E30000DF0000E70000E70000E300
+318E9C318E9C00E30019BA4A19BA4A000000318E9C000000318E9C00000000000000000000000000
+00000000000000000000000000000000005265E60000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFF000000FF
+FFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFF
+FFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000
+FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFF
+FFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000
+000000000000005265E60000000000005265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E652
+65E600000000000000000000000000000000E30000E300318E9C000000000000000000318E9C318E
+9C00E70000DF0000000000000000000000DF0000DB0000DF0000E30000D20000AA00000000000000
+00000000000000000000D70000C20008960000BE00218A004A7508427900527508318200089A0019
+8E0010920000BE00009E00198E00199200089600218A000000000000000000000000000000000000
+00218A00009E00089A0000BE0000AA00109600009E0000000000000000DB0000CA0000A20000AE00
+00D70000A60000BA0000000000D20000C20008960000000000000000000000000000E70000E30000
+E30000E30000E70000E300318E9C318E9C318E9C318E9C00E3000000000000000000000000000000
+000000000000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E60000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000
+000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000
+FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF00
+0000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFF
+FF000000FFFFFFFFFFFFFFFFFF000000FFFFFF000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FFFF00FFFF00FFFF00FFFF00
+FFFF00FFFF000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000000000000000FFFF00FFFF000000000000
+005265E65265E65265E65265E65265E65265E65265E65265E6000000000000318E9C19BA4A000000
+000000000000318E9C318E9C00E30000E30000000000000000DF0000000000E70000000000000000
+000000000000B60000D70000BA00009E0000DB0000BA0000CE00089600089600198E002986006B69
+107B6D215A6D104A75084A790800BE00109600218A00198E00089600218A00298A003A7D00298A00
+318200089600218A00199200218A00089A0010960000CE0000A200009E0008960000CA0000000000
+BA0000B60000AE0000CE0000C20000CE0000B60000BA0000000000C20000000000E3000000000000
+0000000000000019BA4A19BA4A19BA4A00E30000E300318E9C318E9C318E9C000000000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E6000000FFFFFF0000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF000000
+000000000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000000000FFFFFF000000FF
+FFFFFFFFFFFFFFFF000000FFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFF
+FF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000FFFFFFFFFFFF000000
+000000000000000000FFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFF00000000000000
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000FF
+FF00FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E6
+0000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000
+0000000000000000000000000000318E9C318E9C318E9C318E9C00E70000000000E30000DF0000DF
+0000000000DF0000E30000DF0000C200009E0000B600089A00009E00009E0000B20000AE00109600
+2986004A79085271087365196B6919736519218A00198E00009E00218A00089A0029860031820031
+82004279084279004A75083A7D004A7508318200298A00009E00089A0000B20000B200089A0000DB
+0000DB0000C20000C60000000000C60000C20000C60010920000AA0000AA0000D700000000000000
+00DF0000DF0000DF0000000000E30000000000000000E30000E300318E9C318E9C00000000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFF0000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000FFFF00FFFF
+000000000000005265E6000000000000FFFF00FFFF000000000000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6000000000000FFFF00FFFF0000000000
+00005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6000000000000000000000000000000318E9C000000000000000000
+00000000000000E30000E30000DF0000000000DF0000CA0000DB0000CA0000C20000D70008960000
+9E0000B200218A00109200218A004279085A711052711052750831820000B200198E001096001092
+003A7D001992003A82004279007365195A71105A71105A71106B69104279004A750829860000AA00
+00A60000D20000CE0000DB00009E0000C60000000000000000BA0000A600009E0000DB0000DB0000
+D20000000000CA0000E70000DB0000DF0000000000000000E70000E300000000000000318E9C318E
+9C0000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFFFF
+FFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000
+000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E60000000000005265E65265E65265E65265E65265E60000000000005265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E60000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000E30000E70000
+000019BA4A00E30000000000E30019BA4A00000000E70000E30000000000000000000000D70000BE
+0000CA0000CA0000AA0000CE00009E00089600109600089600218A00198E002986003A7D00089600
+009E00089600009E00009E00198E003182003182006B69106B691073651973651973651973651963
+6D104A7908298600009E00009E0000CE0000C20000AA0008960000D20000000000C20000D70000BA
+0000E70000E30000000000000000BA0000CA0000E70000E70000DF0000000000E70000E300318E9C
+318E9C0000000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E6000000FFFFFFFFFFFFFFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6000000000000318E9C00000000000000E30000E30000E300000000000000000000000000
+00DF0000E30000000000000000000000000000000000000000DF0000D20000A60010960000A20000
+C600009E0000A60000A20000D20000DB00089600089A003182004A75085271087369196369107369
+196B69196369107365195A6D103A7D00218A0000A20000A20000A20000B60000B20000BE0000A200
+00000000BE0000CA0000E70000E70000000000E30000BE0000BA0000CA0000E70000DF0000DF0000
+000000E30000E300318E9C318E9C318E9C0000005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E6000000318E9C000000000000318E9C00E30019
+BA4A00000000E70000000000000000DF0000E30000DF0000E30000E70000CA0000BA000000001096
+0000A60000D70000BE0000B20000C600009E0000CE0000D70000A20000A2003182007365197B6919
+6B69197B71217B69217B6D217B6D217B69196B69196369104A7508109600009E0000D70000B60000
+C60000BA0000DB0000B20000C20000000000000000B60000000000E30000E30000E30000BA0000CA
+0000E70000DF0000DF0000000019BA4A318E9C318E9C318E9C0000005265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E6089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000318E
+9C000000318E9C318E9C00E30000000000000000DF0000000000E30000E30000E70000DF0000DB00
+00000000000000E30000E70000AA0000BE0008960000C60000C60000B60000C60000A20010960000
+BE00089A005A71107B79217B71217B71217B79217B79217B75217B69217B69196B6919218A001992
+0000B20000B60000DB0000D20000A20000D20000B60000BE0000000000E30000000000C20000BA00
+00DF0000E70000CE0000E70000E70000DF00000000000000318E9C318E9C318E9C0000005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000
+00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000005265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6000000000000318E9C000000318E9C00000000E30000E70000E70000DF0000000000
+000000000000000000000000000000BE0000E70000D70000D70000DB0010960000AA0000DB00089A
+0000A20000B200109200089A00198E006B69197B75217B7D217B79215A71107B75217B71217B6D21
+7B69215A6D10298600218A0000C20000AE0000B20000C20000CA0000CA0000D70000C20000000000
+CA0000000000BE0000C20000CA0000E30000DB0000DF0000E30000DF0000DF0000000000E300318E
+9C318E9C0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000052
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241428482
+84424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+FFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E6000000318E9C000000318E9C00E70000E7
+0000E30000E30000000000000000E30000E30000DF0000000000D20000B20000B2003182003A7D00
+5A6D107365195275085271083A7D003A7D00109600218A005A71106B69107B75217B7D217B7D217B
+7D217B79217B75217B712173651963691029860000BA0000CE0008960000B200089A0000D20000DB
+0000BE0000CA0000000000E70000000000CA0000CE0000CE0000DF0000E30000E30000DF0000DF00
+00DF000000000000000000000000000000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000
+00000000000000000000000000000000E70000E70000000000E30000E30000E30000000010920021
+8A002986004279005A71107B6D217B6D217B7D217B7D217B6D217B69217365196B69107B65197B71
+217B79217B7D217B79217B75217B75217B6D217365196B6919636910318200109200089A0000CA00
+00D70000BA0000D70000D70000AE0000B60000000000E70000DF0000000000E30000DF0000DF0000
+DF0000E70000E30000000000000000E3000000000000000000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6089600D6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E6000000000000318E9C00E30000000019BA4A00E30000000000E70000DF
+0000000000D200089600009E002986004279085A71105271107365197B79217B7521736519736519
+6369104A79086B69196369107B71217365196B69197B79217B79217B75217B6D216B69104A750831
+820010960000B20000AA0000DB0000CA0000D70000A60000E70000BE0000000000E70000E3000000
+0000000000DF0000E30000E70000E70000000000000019BA4A19BA4A00E300318E9C0000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFF0000005265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600D6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142848284424142FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6
+D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000318E9C000000000000
+00000000000000E70000E30000E30000000000CE0000B200109200218A00218E003A7D006B691952
+71107365194A75083A7D003182003A7D00427D005A71105A71105A6D107B69217B75217B79217B7D
+217B7D217B6519636910318200198E0000BE0010960000BA00089A0010920000AA0000BE0000E300
+00CA0000000000DF0000E30000000000000000000000E70000000019BA4A19BA4A00E300318E9C31
+8E9C0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF0000005265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E6089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84828442
+4142848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+0000000000318E9C318E9C00E30000E30000E30000E30019BA4A00E30000000000000000B2000896
+0000CA0000AE0000B200089600199200009E00009E00089A00318200298A00199200218A004A7508
+6369106B69195A71107B7D217B75217B6D214A7508198E0010920000AE00009E0000BE0000C60000
+AA0000D20000BE0000CA0000CA0000000000000000000000000000000000000000000000000000E3
+0000E30000E30000E300318E9C0000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6000000FFFFFF0000005265E65265E600
+0000FFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E6089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CED6D2CE848284424142848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E6000000318E9C318E9C318E9C318E9C318E9C00E30000E300
+19BA4A00E30000000000000000C200198E0000CE0000B60010960000DF00009E0000B20000A60000
+A600009E00089A004A79084A75085A71107365197369195A6D10527108427908218A0000A20000AA
+0000B60000B60008960000AA00000000000000000000000000000000000000000000000000000000
+00000000000000000019BA4A00E30000E300318E9C318E9C0000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000
+005265E65265E65265E6000000FFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600D6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000318E9C318E9C00
+0000000000000000000000318E9C318E9C318E9C00E30000000000000000000000000000000000CA
+0000B60000DB0000B60000B600009E00009E00089A00218A003A7D002986004A75083A7D00298600
+218A00009E0000CE0000BA0000C60000C60000000000000000E70000BE0000CA0000E70000E30000
+0000000000FFFF00FFFF0000000000000000E30000E30000E300318E9C0000000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E60000005265E65265E65265E65265E65265E6000000FFFFFFFFFFFF0000005265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E6D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFF
+D6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E60000000000000000000000005265E6000000000000000000000000000000000000000000
+19BA4A00E30000000000000000000000000000BE0000B60000C20000AA0000C60000AE00089A0010
+9200089A00109200089A0000CA00089A0000D20000D70010920000000000A60000C20000C60000CA
+0000CE0000DF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000318E9C000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF
+FFFFFFFF0000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E6D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE
+848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6
+D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E600000000000000000000E30000DF0000DF0000000000000000BA0000CE
+0000B20000DB0000000000000000B20000A20000C60000A20000BE0000A20000C60000AE00000000
+00C60000C20000E70000DF0000E30000DF00000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000
+00000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6000000FFFFFFFFFFFF0000005265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6D6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE5265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600000000000000E300
+00DF0000DF00000000000000000000000000FFFF00FFFF00000000000000089A0000BE0000D20000
+B20000C20000000000BA0000DF0000DF0000E30000DF0000DF00000000FFFF00FFFF00FFFF00FFFF
+00FFFF00FFFF00FFFF00FFFF000000005265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E6000000FFFFFFFFFFFF0000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6D6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFF
+FFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE52
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E600000000000000000000E300000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+0000000000E70000DF0000BA0000DF0000000000DF0000E30000E30000E30000E30000E300000000
+FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600
+089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6
+D2CEFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2
+CEFFFFFFD6D2CED6D2CE5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+00000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000000000FFFF00FFFF00
+FFFF00FFFF00FFFF00FFFF0000000000DF0000CE0000000000000000DF0000E30000E30000DF0000
+E70019BA4A00E30000E700000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E608960008960008960008960008960008960008
+9600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE5265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E60000000000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E600
+0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF0000000000000000E30000E70000E3
+0000E70000E30019BA4A000000000000000000000000000000FFFF00FFFF00FFFF00FFFF00FFFF00
+FFFF000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E60896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFF000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE5265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00000000
+0000000000000000000000000000000000000000005265E65265E65265E65265E65265E600000000
+0000FFFF00FFFF000000000000005265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600089600D6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFF
+FFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CE
+D6D2CE5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E60000000000005265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF00FFFF00FFFF00FFFF00FF
+FF00FFFF000000005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E60000000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E6089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284
+424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFF
+FFFFD6D2CEFFFFFFD6D2CED6D2CE5265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000FFFF
+00FFFF00FFFF00FFFF00FFFF00FFFF000000005265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E6089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE5265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E6000000000000FFFF00FFFF000000000000005265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFF
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE5265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFF
+FFD6D2CED6D2CE0896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E60000005265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E608960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2
+CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+D6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+000896005265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E60000000000005265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+000896000896000896000896000896000896000896000896000896000896000896005265E65265E6
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265
+E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E6000000
+5265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E65265E652
+65E65265E65265E65265E65265E65265E65265E65265E60896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600089600D6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6
+D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6
+D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000
+00000000000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFF
+FFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000
+0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE8482844241
+42D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF000000000000FFFFFFFFFFFF
+000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF00
+0000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF00
+0000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFF0000
+00000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2
+CED6D2CE089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142D6D2CEFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000
+000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FF
+FFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFF
+FF000000000000FFFFFF000000000000000000000000000000000000000000000000000000FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CE
+FFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFF
+D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF000000000000FFFFFFFFFFFF000000000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFF000000000000000000FFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFF
+FFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000000000FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FF
+FFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84
+8284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF000000000000FFFF
+FFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFF
+FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFF000000000000FFFF
+FFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CE
+FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFF
+FFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF0000
+00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF
+FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFF
+FFFFD6D2CED6D2CE0896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6
+D2CE848284424142D6D2CEFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000
+000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000
+0000000000FFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF0000
+00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2
+CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF000000000000FFFFFFFFFFFF000000
+000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF00000000
+0000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFF000000000000FFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000
+000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600D6D2CE
+D6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFF00
+0000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000
+00000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000FFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFF00000000
+0000FFFFFFFFFFFF000000000000FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2
+CE089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482844241
+42D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFF
+D6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CE
+D6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE84828442
+4142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CEFFFFFFD6
+D2CED6D2CE0896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CE84
+8284424142D6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2
+CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600089600089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFF
+FFD6D2CED6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CEFFFFFFD6D2CED6D2CE08960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600D6D2CED6D2CE
+848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CEFFFFFFD6D2CED6D2CE0896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+9600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+FFFFFFD6D2CED6D2CE08960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600089600089600089600089600089600089600089600089600
+08960008960008960008960008960008960008960008960008960008960008960008960008960008
+96000896000896000896000896000896000896000896000896000896000896000896000896000896
+00089600089600089600089600089600D6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6
+D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+848284848284FFFFFFD6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2
+CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CE848284
+424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFF
+FFFFD6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284
+D6D2CED6D2CE000000D6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CE00
+0000000000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE0000000000000000
+00D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CE000000000000000000000000000000
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CE00
+0000000000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CE0000000000000000000000
+00000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000000000
+000000D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6
+D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE0000
+00000000000000000000000000D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000000000D6D2CED6D2CE000000000000000000000000000000D6
+D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142D6D2CEFF
+FFFFD6D2CED6D2CE848284D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE
+000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE
+000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2
+CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000
+000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE00
+0000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000000000D6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284D6D2CED6D2CED6D2
+CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CE000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6
+D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2
+CE000000D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6
+D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6
+D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6
+D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284
+848284D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CE000000D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000000000000000000000D6D2
+CED6D2CED6D2CE000000000000000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000000000000000000000D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE000000000000000000000000D6D2CED6D2CE000000000000000000000000D6D2
+CED6D2CED6D2CE000000000000000000D6D2CED6D2CE000000000000000000000000D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE00
+0000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000000000000000D6D2CED6D2CE000000D6D2
+CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE
+000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2
+CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CEFFFFFF848284848284D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2
+CE848284D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000
+D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE00000000
+0000000000000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CE000000
+D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6
+D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE
+000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000000000000000000000000000D6
+D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2
+CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CED6D2CE000000000000000000000000000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFFFFD6D2CED6D2CED6D2CE848284424142
+D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6
+D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE00
+0000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2
+CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE
+D6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6
+D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2
+CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFFFF848284D6D2CED6
+D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CE000000D6D2CED6D2CED6D2
+CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000
+D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6
+D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2
+CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000
+D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2
+CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CE000000D6D2CED6D2CED6D2CE
+000000D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6
+D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2
+CED6D2CE000000D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000
+D6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFF
+FF848284848284D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CE
+D6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CE00000000000000
+0000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000000000D6D2CED6D2
+CED6D2CE000000000000000000000000000000D6D2CED6D2CE000000000000000000D6D2CED6D2CE
+D6D2CE000000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE00000000000000
+0000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000000000000000D6D2
+CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6
+D2CE000000000000000000D6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE0000
+00D6D2CED6D2CED6D2CED6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000D6D2CE
+D6D2CED6D2CE000000000000000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284
+848284D6D2CEFFFFFF848284848284D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6
+D2CED6D2CE848284D6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CEFFFFFF848284848284D6D2CEFFFFFF848284848284D6D2CEFFFFFFD6D2CED6D2CED6D2CE8482
+84424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE000000D6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE00
+0000D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFFFF848284848284D6D2CEFFFFFF848284
+D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE848284D6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFFFF848284848284D6
+D2CEFFFFFF848284848284D6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CE8482
+84D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CEFFFFFF848284848284D6D2CEFFFF
+FF848284848284D6D2CEFFFFFF848284848284D6D2CED6D2CED6D2CED6D2CE848284424142D6D2CE
+FFFFFFD6D2CED6D2CEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CEFFFFFFD6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6
+D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2
+CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE
+D6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CED6D2CE848284424142D6D2CE84828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482848482
+84848284848284848284848284848284848284848284848284848284848284848284848284848284
+84828484828484828484828484828484828484828484828484828484828484828484828484828484
+82848482848482848482848482848482848482848482848482848482848482848482848482844241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+42414242414242414242414242414242414242414242414242414242414242414242414242414242
+41424241424241424241424241424241424241424241424241424241424241424241424241424241
+42424142424142424142424142424142424142424142424142424142424142424142424142424142
+424142424142424142424142
+%%EndData
+[106 0 0 -23 397 89] rect
+gsave
+1 0 0 rgb
+F
+grestore
+0 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+/Helvetica-Bold 14 sf
+(Map Window)
+406 72 1 1 1 rgb
+T
+[67 0 0 -23 155.348 180.826] rect
+gsave
+1 0 0 rgb
+F
+grestore
+0 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+/Helvetica-Bold 14 sf
+(Legend)
+164.348 163.826 1 1 1 rgb
+T
+[77 0 0 -23 315.391 319.522] rect
+gsave
+1 0 0 rgb
+F
+grestore
+0 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+/Helvetica-Bold 14 sf
+(Tool Bar)
+324.391 302.522 1 1 1 rgb
+T
+[87 0 0 -23 203.739 60.7391] rect
+gsave
+1 0 0 rgb
+F
+grestore
+0 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+/Helvetica-Bold 14 sf
+(Status Bar)
+212.739 43.7391 1 1 1 rgb
+T
+%%PageTrailer
+showpage
+%%Trailer
+end
+%%DocumentSuppliedResources: procset Linux-Sketch-Procset 1.0 2
+%%EOF
Added: packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.sk
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.sk 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/images/1_2_mainwindow.sk 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,52 @@
+##Sketch 1 2
+document()
+layout((540,400),0)
+layer('Layer 1',1,1,0,0,(0,0,0))
+bm(140059220,'../../../../../../.gnome-desktop/Screenshot-2.png')
+im((19.6378,35.9449),140059220)
+G()
+fp((1,0,0))
+lw(1)
+r(106,0,0,-23,397,89)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Bold')
+Fs(14)
+txt('Map Window',(406,72))
+G_()
+G()
+fp((1,0,0))
+lw(1)
+r(67,0,0,-23,155.348,180.826)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Bold')
+Fs(14)
+txt('Legend',(164.348,163.826))
+G_()
+G()
+fp((1,0,0))
+lw(1)
+r(77,0,0,-23,315.391,319.522)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Bold')
+Fs(14)
+txt('Tool Bar',(324.391,302.522))
+G_()
+G()
+fp((1,0,0))
+lw(1)
+r(87,0,0,-23,203.739,60.7391)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Bold')
+Fs(14)
+txt('Status Bar',(212.739,43.7391))
+G_()
+guidelayer('Guide Lines',1,0,0,1,(0,0,1))
+grid((0,0,20,20),0,(0,0,1),'Grid')
Added: packages/thuban/branches/upstream/current/Doc/manual/images/2_4_session_tree.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/2_4_session_tree.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullextent.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullextent.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fulllayerextent.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fulllayerextent.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullshapeextent.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_fullshapeextent.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_pan.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_pan.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomin.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomin.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomout.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_2_zoomout.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_3_identify.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_3_identify.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_3_label.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_3_label.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_invisible.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_invisible.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_legend.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_legend.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_movedown.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_movedown.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_moveup.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_moveup.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_popup_menu.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_popup_menu.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_props.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_props.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_tobottom.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_tobottom.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_totop.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_totop.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_visible.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_5_visible.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/3_rename_map.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/3_rename_map.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/4_2_layer_properties.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/4_2_layer_properties.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/4_2_raster_layer_properties.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/4_2_raster_layer_properties.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_custom_ramp.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_custom_ramp.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_quantiles.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_quantiles.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_uniform_dist.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_uniform_dist.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_unique_values.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_2_unique_values.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_3_genclass.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_3_genclass.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/5_classification.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/5_classification.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/6_projection.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/6_projection.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/7_1_table_view.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/7_1_table_view.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/7_2_5_join.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/7_2_5_join.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/8_int_error.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/8_int_error.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_add_layer.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_add_layer.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_add.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_add.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_management.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/images/app_postgis_db_management.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/mainwindow.png
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/mainwindow.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/mainwindow.xcf
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Doc/manual/mainwindow.xcf
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Doc/manual/thuban-manual-de.xml
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/thuban-manual-de.xml 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/thuban-manual-de.xml 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,2400 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book
+ PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY imgscale "60">]>
+<!-- $Revision: 2627 $ -->
+<book>
+ <bookinfo>
+ <title>Benutzerhandbuch für Thuban 1.0</title>
+ <authorgroup>
+ <author>
+ <firstname>Jonathan</firstname><surname>Coles</surname>
+ </author>
+ <author>
+ <firstname>Jan-Oliver</firstname><surname>Wagner</surname>
+ </author>
+ <author>
+ <firstname>Frank</firstname><surname>Koormann</surname>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2004</year>
+ <holder>Intevation GmbH</holder>
+ </copyright>
+ <revhistory>
+<!-- comment this first revision out when releasing a real version -->
+ <revision>
+ <revnumber>CVS version $Id: thuban-manual-de.xml 2627 2005-06-27 15:52:08Z jan $</revnumber>
+ <date></date>
+ <revremark>Under development.</revremark>
+ </revision>
+<!--
+ <revision>
+ <revnumber>1.0.0</revnumber>
+ <date>nn-Mmm-2004</date>
+ <revremark>
+ Corresponds to Thuban 1.0.0.
+ </revremark>
+ </revision>
+-->
+ </revhistory>
+
+ </bookinfo>
+
+ <chapter><title>Einführung</title>
+ <para>
+ Thuban ist ein interaktiver Geodaten-Betrachter.
+ Die Entwicklung wurde seinerzeit gestartet, da es zu dieser Zeit
+ keinen einfachen interkativen Betrachter für Geo-Daten als Freie
+ Software gab.
+ Thuban ist im wesentlichen in der Programmiersprache Python implementiert und
+ nutzt die wxWidgets (ehemals: wxWindows) Bibliothek die es erlaubt
+ Thuban auf verschiedenen Plattformen laufen zu lassen, darunter GNU/Linux
+ und Windows.
+ </para>
+ <para>
+ Geodatenbetrachter sind wichtige Werkzeuge die es gestatten, einen visuelle
+ Eindruck des räumlichen (gegenseiten) Bezuges von Informationen zu bekommen
+ die ansonsten anhand der reinen Daten nicht leicht ersichtlich sind.
+ Thuban erlaubt dem Benutzer, Sitzungen zu erzeugen, die geografische
+ Daten darstellen. Diese können dann erforscht werden indem er durch sie
+ sie navigieren und die Art der Darstellung ändern kann.
+ Die Ergebnisse können gespeichert oder gedruckt werden.
+ </para>
+ <para>
+ Thuban strukturiert eine Sitzung hierarchisch.
+ Eine Sitzung besteht aus Ebenen. Jede Ebene rerpäsentiert
+ einen bestimmten Datensatz.
+ Beispielsweise eine Ebene für Strassen und eine weitere für Gebäude.
+ Die Ebenen können sowohl Vektor-Daten beschreiben als auch Raster-Daten.
+ </para>
+
+ <section><title>Installation</title>
+ <para>
+ Thuban is actively supported under Debian Testing (sarge), RedHat 7.2,
+ and Windows 2000. Thuban depends on the following packages. These
+ packages can also be found on the
+ <ulink url="http://thuban.intevation.org/download.html">
+ Thuban Download site
+ </ulink>.
+ </para>
+ <para>
+ Required:
+ <itemizedlist>
+ <listitem><para>Python 2.2.1
+ (<literal>http://www.python.org</literal>)
+ </para></listitem>
+ <listitem><para>wxWindows 2.4
+ (<literal>http://www.wxwindows.org</literal>)
+ </para></listitem>
+ <listitem><para>wxPython 2.4
+ (<literal>http://www.wxpython.org</literal>)
+ </para></listitem>
+ <listitem><para>proj 4.4.5 Projection Library
+ (<literal>http://www.remotesensing.org/proj/</literal>)
+ </para></listitem>
+ <listitem><para>SQLite 2.8.3
+ <literal>http://www.hwaci.com/sw/sqlite/</literal>)
+ </para></listitem>
+ <listitem><para>PySQLite 0.4.3
+ (<literal>http://pysqlite.sourceforge.net</literal>)
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Optional:
+ <itemizedlist>
+ <listitem><para>GDAL 1.1.8
+ (<literal>http://www.remotesensing.org/gdal/</literal>)
+ </para></listitem>
+ <listitem><para>psycopg 1.0.8
+ (<literal>http://initd.org/software/psycopg</literal>)
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Along with the source codes, the download page also offers full
+ installation packages for Debian, Windows and RPM-based systems
+ (Mandrake, RedHat, SuSE, etc).
+ </para>
+ <section><title>RPM-based GNU/Linux Systems</title>
+ <section><title>Installing Binary Packages</title>
+ <para>
+ The most wide-spread RPM-based GNU/Linux
+ Systems are RedHat, Mandrake and SuSE.
+ The documentation of these distributions
+ should contain information about how to
+ install third-party RPM packages.
+ Nonetheless, a short summary is provided here.
+ </para>
+ <para>
+ RPM packages can be installed applying several
+ tools. The most basic one is the command line
+ program "rpm". The hardware architecture is
+ identified in the name of RPM packages, eg.
+ 'i386' for most Intel/AMD architectures.
+ If you have a different hardware architecture,
+ where no binary RPM packages are provided,
+ you must rebuild binary packages from the
+ RPM source packages first (see below).
+ Typical rpm commands look like:
+
+ <programlisting>
+ rpm --install Thuban-0.9.0-1.i386.rpm
+ </programlisting>
+
+ Depending on what you already have installed
+ on your system, you are informed that some
+ packages are required, but not installed.
+ You need to install them first. Either they
+ are provided by your GNU/Linux distributor
+ or available somewhere on the Internet.
+ The more essential and special ones are
+ provided together with the Thuban package.
+ </para>
+
+ <para>
+ For rpm exist some graphical user interfaces, notably
+ kpackage, GnoRPM and xrpm.
+ </para>
+
+ <para>
+ Make yourself familiar with one of the tools and apply it
+ to install the packages.
+ Note, that you need to be administrator (root) for the system
+ to do that.
+ </para>
+ </section>
+ <section><title>Build Binaries from Source Packages</title>
+ <para>
+ This section describes howto build RPM install-packages
+ from RPM source-packages.
+ This adapts and optimizes an install-package specifically
+ to your system.
+ This is especially helpful to resolve version conflicts of
+ dependent packages. Furthermore, install-packages for other
+ platforms (e.g. PowerPC) can be created.
+ </para>
+
+ <para>
+ Note: rpm must be at least version 4. Execute
+ <literal>rpm --version</literal> to find out about the version.
+ </para>
+
+ <para>
+ You need to do the following preparations to be able to
+ build the packages as a regular user. You should now
+ perform the package buling as root since this
+ might cause damage to your system.
+ <itemizedlist>
+ <listitem>
+ <para>
+ Create RPM directory structure:
+ Choose a directory (e.g. $HOME/myrpm) and create the
+ subdirectories BUILD, RPM, SOURCES, SPECS and SRPMS.
+ A possible command sequence for this is:
+ <programlisting>
+ mkdir $HOME/freegisrpm
+ cd $HOME/freegisrpm
+ mkdir BUILD RPMS SOURCES SPECS SRPMS
+ </programlisting>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set environment variable RPM_DIR:
+ <programlisting>
+ export RPM_DIR=$HOME/freegisrpm
+ </programlisting>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Create $HOME/.rpmmacros:
+ This file sets general preferences and some
+ specific settings for signing packages.
+ If you don't have a GnuPG-key, you can skip
+ the signature settings i.e. drop the last 4 lines.
+ A signature becomes important when you want to
+ give away packages to third parties.
+ <programlisting>
+<![CDATA[
+%packager Name Lastname <Name.Lastname at mydomain.example>
+
+%_topdir /home/mylogin/myrpm
+
+%_signature gpg
+%_gpg_name Name Lastname
+%_pgp_path ~/.gnupg
+%_pgpbin /usr/bin/gpg
+]]>
+ </programlisting>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ Now you can install any RPM source-package.
+ It's components are installed into the corresponding
+ subdirectories of your rpm-directory.
+ Essentially these are the sources (into directory SOURCES)
+ and the so-called spec-file which contains all build
+ instructions. The spec-file will go into the SPEC directory.
+ Example:
+ <literal>rpm --install Thuban-0.9.0-1.src.rpm</literal>
+ </para>
+
+ <para>
+ Create install-package:
+ Go to the directory with the spec-files and rebuild the
+ package:
+ <programlisting>
+cd $HOME/mypm/SPECS
+rpm -bb thuban.spec
+ </programlisting>
+ Next, you will find the newly created package in
+ $HOME/myrpm/RPMS/i386.
+ If you build the package for another architecture than
+ i386, then the name of the directory has a corresponding name.
+ </para>
+ <para>
+ For documentation of RPM, either type
+ <literal>man rpm</literal> or <literal>rpm --help</literal>.
+ This will provide you with information on the various command
+ line options of RPM.
+ For more information see the
+ <ulink url="http://www.rpm.org/">homepage of RPM</ulink>.
+ </para>
+ </section>
+ </section> <!-- Intro - Installation - RPM-->
+
+ <section><title>Win32 Systems</title>
+ <para>
+ A common installation package of Thuban for Win32
+ systems is available from the Thuban website download
+ section. This installation package is configured for
+ displaying file based vector data (Shapefiles). For the
+ display of raster data or the connection to spatial
+ databases additional steps are needed.
+ </para>
+ <para>
+ The required Python packages are listed and linked on
+ the download page as well. If you don't have Python
+ installed already, download the packages for Python,
+ wxPython for Python and the SQLite Python Libraries as
+ well as the Thuban package. Install all four packages
+ in the order: Python, wxPython, SQLite, Thuban. Follow
+ the installation instructions provided by the seperate
+ setups. The Thuban installation package will add an
+ entry in the menu folder you configured.
+ </para>
+ <section><title>Raster Data: Installation of GDAL</title>
+ <para>
+ Enabling the raster data features of Thuban is
+ straight forward. For the examples we assume that
+ Thuban has been installed under
+ <literal>C:\Thuban</literal>:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Download the zip-archive <ulink
+ url="ftp://intevation.de/thuban/win2k/gdal-win2k.zip"
+ >gdal-win2k</ulink>.
+ </para></listitem>
+ <listitem><para>Extract the archive (e.g. with
+ <ulink
+ url="http://www.info-zip.org/pub/infozip/WiZ.html"
+ >WiZ (InfoZip)</ulink>) into the
+ <literal>C:\Thuban\Lib</literal>
+ directory of your Thuban installation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Extent the <varname>PYTHONPATH</varname>
+ environment variable (in your Windows Control Panel)
+ to make the new libraries available for Thuban.
+ <programlisting>
+%PYTHONPATH%;C:\Thuban\Lib\gdal;C:\Thuban\Lib\gdal\pymod
+ </programlisting>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Extent also the <varname>PATH</varname>
+ environment variable accordingly:
+ <programlisting>
+%PATH%;C:\Thuban\Lib\gdal
+ </programlisting>
+ </para>
+ </listitem>
+ </itemizedlist>
+ After this installation steps Thuban is ready to
+ display raster data (e.g. the
+ <literal>island.tif</literal> from the Iceland Demo
+ data set.
+ </para>
+ </section> <!-- Win32: GDAL-->
+
+ <section><title>Working with PostGIS: Installation of PsycoPG</title>
+ <para>
+ To access PostgreSQL/PostGIS spatial databases with
+ Thuban you have to install the PsycoPG package for
+ Windows:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Download the zip-archive
+ <ulink
+ url="http://stickpeople.com/projects/python/win-psycopg/win-psycopg22.zip"
+ >win-psycopg22.zip</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Extract the zip-archive into a directory either already
+ in your <varname>PYTHONPATH</varname> or extent your
+ <varname>PYTHONPATH</varname> variable to the directory
+ you have extracted the archive to.
+ </para>
+ </listitem>
+ </itemizedlist>
+ For installation and maintenance of spatial databases
+ we refer to the <ulink
+ url="http://postgis.refractions.net"
+ >PostGIS Homepage</ulink>.
+ </para>
+ </section> <!-- Win32: PsycoPG-->
+
+ </section> <!-- Intro - Installation - Win32 -->
+ </section>
+
+ <section><title>Internationalisierung</title>
+ <para>
+ Thuban ist mit Unterstützung für Internaionalisierung realisiert.
+ Bisher wurde Thuban in folgende Sprachen (neben der Basis Englisch) übersetzt:
+ <itemizedlist>
+ <listitem><para>Französisch</para></listitem>
+ <listitem><para>Deutsch</para></listitem>
+ <listitem><para>Italienisch</para></listitem>
+ <listitem><para>Portugiesisch (Brasilien)</para></listitem>
+ <listitem><para>Russisch</para></listitem>
+ <listitem><para>Spanisch</para></listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ Um die Internationalisierung auf POSIX Systemen (wie etwa GNU/Linux)
+ zu verwenden, muss die Umgebungsvariable LC_ALL entsprechend
+ gesetzt werden (z.B. LC_ALL=de_DE für Deutsch).
+ Prüfen Sie die Dokumentation zu Ihrem System für Details
+ und die unterstützten Einstellungen.
+ Normalweise haben Sie Ihre Sprache bereits mit der Installation
+ oder beim einloggen bereits vorausgewählt.
+ Trotzdem kann auch dann noch durch Setzen von LC_ALL auf
+ der Kommandozeile beim Aufruf von Thuban eine andere Sprache
+ gesetzt werden:
+ </para>
+ <programlisting>
+ LC_ALL=fr_FR thuban.py
+ </programlisting>
+
+ <para>
+ MS Windows Benutzer müssen die Sprache über die Kontroll-Leiste einstellen
+ welche grundsätzlich alle Anwendungen beeinflusst.
+ </para>
+ </section>
+
+ <section><title>Das Hauptfenster</title>
+ <para>
+ <figure><title>Das Hauptfenster</title>
+ <mediaobject>
+ <imageobject> <imagedata fileref="../images/1_2_mainwindow.png" format="PNG" scale="&imgscale;"/> </imageobject>
+ <imageobject> <imagedata fileref="./images/1_2_mainwindow.ps" format="EPS" scale="&imgscale;"/> </imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ <para>
+ Das Hauptfenster stellt die aktuelle Karte dar. Hier kann der
+ Benutzer mit der Karte interagieren indem er die verschiednen
+ Werkzeuge anwendet.
+ </para>
+
+ <para>
+ Die Legende auf der linken Seite zeigt eine Liste der aktuellen
+ Ebenen und alle dargestellten Klassifikations-Gruppen.
+ Bei diesem Beispiel haben alle Geo-Objekte Ebenen eine voreingestellte
+ Klassifizierung wie die jeweiligen Geo-Objekte in den einzelnen
+ Ebenen gezeichnet werden sollen.
+ Die Ebenen die weiter oben in der Liste dargestellt werden über
+ die darunter aufgelisteten gezeichnet.
+ Die Legende kann durch Anwahl des X in der oberen rechten Ecke
+ geschlossen werden.
+ Um die Legenden-Ansicht wieder zu öffnen, wählen Sie
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Legende</guimenuitem>
+ </menuchoice>.
+ Das Legenden-Fenster ist lösbar. Das bedeutet, dass sie vom Hauptfenster
+ abgelöst und dann als eigenständiges Fenster
+ positioniert werden kann. Dies wird durch den kleinen Schalter
+ neben dem X gemacht. Erneutes Anwählen des Schalters läßt das
+ Legenden-Fenster wieder in das Hauptfenster integrieren.
+ </para>
+ <para>
+ Die Status-Leiste zeigt verschiedene Informationen jeweils
+ abhängig vom Kontext. Wählt der Benutzer einen Menüpunkt
+ dann wird in der Status-Leiste ein Hilfetext zu dem jeweiligen
+ Menüpunkt angezeigt.
+ Ist eines der Werkzeuge aktiviert, so wird in der Status-Leiste
+ die Position angegeben über der der Maus-Cursor auf der Karte
+ steht.
+ </para>
+ <para>
+ Die Werkzeugleiste erlaubt direkten Zugriff auf häufig
+ benötigte Werkzeuge.
+ Schwebt der Maus-Zeiger über einem Knopf wird eine Kurz-Info
+ über das jeweilige Werkzeug gegeben.
+ Folgende Werzeuge stehen zur Verfügung: Hineinzoomen,
+ Herauszoomen, Verschieben, Zur vollen Kartenausdehnung zoomen,
+ Zur vollen Ebenenausdehnung zoomen, Zur vollen Auswahlausdehnung zoomen,
+ Identifizieren, Labels hinzufügen/entfernen.
+ Alle Werkzeuge werden in diesem Handbuch noch detaillierter beschrieben.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Session Management</title>
+
+ <section><title>Eine neue Session beginnen</title>
+ <para>
+ Eine neue Session wird gestartet über
+ <menuchoice>
+ <guimenu>Datei</guimenu>
+ <guimenuitem>Neue Session</guimenuitem>
+ </menuchoice>.
+ Falls bereits eine Session geladen ist und seit der letzten
+ Speicherung verändert wurde, so wird nun nachgefragt, ob
+ diese Session zunächst gespeichert werden soll.
+ Eine neue Session besteht aus einer leeren Karte
+ ohne Ebenen, Tabellen und Projektion.
+ </para>
+ </section>
+
+ <section><title>Eine Session öffnen</title>
+ <para>
+ Eine Session kann geöffnet werden über
+ <menuchoice>
+ <guimenu>Datei</guimenu>
+ <guimenuitem>Öffne Session</guimenuitem>
+ </menuchoice>.
+ Es wird ein Dateiauswahl-Dialog geöffnet um eine
+ Thuban Session Datei auszuwählen. Diese Dateien enden
+ auf <varname>.thuban</varname>. Wird eine Datei ausgewählt und mit
+ <guibutton>OK</guibutton> bestätigt, so wird die entsprechende
+ Session in Thuban geladen.
+
+ Ist bereits eine Session geladen und seit dem letzten Speichern modifiziert
+ worden, so wird nachgefragt, ob zunächst die alte Session gespeichert werden
+ soll.
+ </para>
+ </section>
+
+ <section><title>Eine Session speichern</title>
+ <para>
+ Eine Session kann gepsiechert werden über
+ <menuchoice>
+ <guimenu>Datei</guimenu>
+ <guimenuitem>Session Speichern</guimenuitem>
+ </menuchoice>.
+ Handelt es sich bei der aktuellen Session nicht um eine
+ neue und ungespeicherte, so wird die entsprechende Datei
+ mit den Daten der aktuellen Session überschrieben.
+ Im Falle einer neuen und noch nicht gespeicherten Session
+ wird ein Dateiauswahl-Dialog geöffnet um einen Namen
+ für die zu speicherende Session auszuwählen.
+ Thuban Session Dateien sollten mit der Endung
+ <varname>.thuban</varname> versehen werden.
+ Existiert bereits eine Datei mit dem gleichen Namen
+ wird der Benutzer gefragt ob diese überschrieben
+ oder ein neuer Name gewählt werden soll.
+ </para>
+ </section>
+
+ <section><title>Der Session Info-Baum</title>
+ <para>
+ <figure>
+ <title>Session Info-Baum</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/2_4_session_tree.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/2_4_session_tree.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Der Session Info-Baum ist hauptsächlich für Software-Entwickler gedacht
+ die an Thuban arbeiten.
+ Er stellt eine Reihe von internen Daten zur Session, der Karte, den
+ Ebenen usw. dar. Er wird geöffnet über
+ <menuchoice>
+ <guimenu>Datei</guimenu>
+ <guimenuitem>Session Baum</guimenuitem>
+ </menuchoice>.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Karten Management</title>
+ <para>
+ Die Karte besteht aus eine Anzahl Ebenen wobei jede Ebene einen
+ Datensatz mit bestimtem Typ repräsentiert. Mit Interaktion auf der
+ Karte kann ein Benutzer die Daten visuell erforschen.
+ </para>
+ <para>
+ Die Karte kann einen Namen haben der dann in der Kopfzeile des
+ Thuban Fensters auftaucht. Der Kartenname kann geändert werden
+ über
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Umbennen</guimenuitem>
+ </menuchoice>.
+ </para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_rename_map.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_rename_map.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Karte umbennen</phrase> </textobject>
+ </inlinemediaobject>
+ </para>
+
+ <section><title>Hinzufügen und Entfernen von Ebenen</title>
+ <para>
+ Es gibt drei Typen von Ebenen aus denen eine Karte besteht:
+ Shape Ebene, Datenbank Ebene und Bildebene.
+ Shape Ebenen sind im Shapefile Format gespeichert welches
+ weit verbreitet für die Speicherung von geografischen Objekten
+ genutzt wird.
+ Die Dateien haben die Endung ``.shp''. Mit der eigentlichen Shape
+ Datei ist eine Datenbank Datei welche die Attribut-Daten zu dem
+ Shapefile enthält. Diese Datenbank Datei verwendet das dBase Format
+ und hat die Endung ``.dbf''. Beide Dateien müssen den selben
+ Basisnamen haben. So gehören zum Beispiel die Dateien
+ strassen.shp und strassen.dbf zusammen.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Shape Ebenen können zur Karte hinzugefügt werden mit
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Ebene hinzufügen</guimenuitem>
+ </menuchoice>.
+ Zunächst werden im Dateiauswahl Dialog nur die ``.shp'' Dateien
+ angezeigt, was für die Auswahl vollkommen ausreicht.
+ Falls Sie aber auf Ansicht aller Dateien umschalten, und dann
+ einer der assoziierten Dateien (z.B. mit der Endung ``.dbf'')
+ auswählen, so verwendet Thuban den Basisnamen um die entsprechende
+ Shape Datei zu laden,
+ </para>
+ <para>
+ Der Dateidialog für Shape Dateien erlaubt es auch, viele
+ Dateien gleichzeitig auszuwählen. Verwenden Sie dafür
+ die Umschalt-Taste gleichzeitig mit der linken Maustaste um
+ die Auswahl zu erweitern.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Datenbankebenen können zu Karte hinzugefügt werden mit
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Datenbankebene hinzufügen</guimenuitem>
+ </menuchoice>.
+ Es wird ein Dialog mit zwei Listen geöffnet.
+ Die linke Liste zeigt alle derzeit offenen Datenbankverbindungen dieser
+ Session an. Eine Liste der verfügbaren Ebenen aus einer Datenbankverbindung
+ wird steht auf der rechten Seite. Aus dieser Liste können Sie eine
+ beliebige Ebene zum Öffnen auswählen. Der Dialog wird dabach
+ automatisch beendet.
+ </para>
+ <para>
+ Siehe auch Anhang ``Mit PostGIS arbeiten'' für weitere Details.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Bildebenen können zur Karte hinzugefügt werden mit
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Bildebene hinzufügen</guimenuitem>
+ </menuchoice>.
+ Es ist wichtig, dass eine korrekte Bilddatei ausgewählt für
+ die auch geographische Daten (Projektions) vorliegen.
+ Diese Daten können in die Bilddatei eingebettet sein oder
+ als separate Datei vorliegen. Können diese Daten nicht
+ gefunden werden, so wird Thuban einen Fehler melden.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section><title>Navigation</title>
+ <para>
+ Die Karte kann erforscht werden indem die Navigationswerkzeuge
+ aus der Werkzeugleiste oder über das Menü
+ <menuchoice><guimenu>Karte</guimenu></menuchoice> ausgewählt werden.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Das ZoomIn Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_zoomin.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_zoomin.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>ZoomIn Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ vergrößert einen Bereich aus der Karte. Ein einmaliges Klicken auf
+ die Karte vergrößert die Karte um das Doppelte und zentriert auf den
+ angewählten Punkt. Klicken und Ziehen selektiert einen Bereich
+ der dann so vergrößert wird, dass er das Fenster ausfüllt.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Das ZoomOut Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_zoomout.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_zoomout.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>ZoomOut Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ verkleinert die Karte, so dass ein größerer Bereich zu sehen ist.
+ Ein einzelnen Klick verkleinert die Karte um Faktor 2.
+ Klicken und Ziehen selektiert einen Bereich in den die gesamte sichtbare
+ Karte im Fenster hineinverkleinert wird.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Das Verschieben Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_pan.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_pan.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Verschieben Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ gestattet es dem Benutzer die Karte durch klicken und
+ ziehen mit gedrückter Maustaste zu verschieben.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Das Volle Ausdehnung Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fullextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fullextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Volle Ausdehnung Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ skaliert die Zoom-Stufe so, dass die gesamte sichtbare Karte im
+ Fenster dargestellt wird.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Das Voll Ebenen-Ausdehnung Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fulllayerextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fulllayerextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Volle Ebenen-Ausdehnung Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ skaliert die Zoom-Stufe so, dass die akutelle Ebene vollständig
+ im Fenster dargestellt wird. Ist keine Ebene ausgewählt, so
+ ist dieser Knopf ausgegraut und damit nicht verfügbar.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Das Volle Shape-Ausdehnung Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fullshapeextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fullshapeextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Volle Shape-Ausdehnung Werkzeug</phrase> </textobject>
+ </inlinemediaobject>
+ skaliert die Zoom-Stufe so, dass die aktuell ausgewählten Shapes
+ vollständig in das Fenster eingepasst sind.
+ Handelt es sich bei der Auswahl nur um einen einzelnen Punkt
+ so wird dieser zentriert dargestellt und bis zu einem gewissen
+ grad gezoomed.
+ Ist kein Shape selektiert, so ist dieser Knopf ausgegraut und damit
+ nicht verfügbar.
+ Dieses Werkzeug ist besonders für den Fall hilfreich wenn man Objekte
+ in einer Ebenen-Tabelle auswählt und sie auf der Karte schnell
+ anspringen machen möchte.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section><title>Objekt Identifikation</title>
+ <para>
+ Objekte auf der Karte können identifiziert werden über das Identifikations-Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_3_identify.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_3_identify.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Identifikations-Werkzeug</phrase> </textobject>
+ </inlinemediaobject>.
+ Klickt man auf ein Objekt wird es selektiert und es wird ein
+ Dialog geöffnet der dann alle Tabellenattribute für das Objekt
+ anzeigt. Jegliche vorherige Selektion wird gelöscht.
+ Objekte auf der Karte sind typischerweise Shapes und dieses
+ Dokument wird sich häufiger auf Objekte als Shapes beziehen.
+ </para>
+ </section>
+
+ <section><title>Objekt mit Label versehen</title>
+ <para>
+ Objekte können über das Label-Werkzeug mit Labeln versehen
+ werden
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_3_label.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_3_label.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Label Werkzeug</phrase> </textobject>
+ </inlinemediaobject>.
+ Klickt man auf ein Objekt, so wird dies selektiert und es wird ein
+ Dialog geöffnet welcher dessen Attribute darstellt.
+ Eins der Attribute kann nun als Label für das Objekt auf der Karte
+ ausgewählt werden. Der Label wird dann mittif auf dem Shape
+ plaziert.
+ Klickt man auf ein Objekt welches bereits ein
+ Label hat, so wird dieser nun entfernt.
+ </para>
+ </section>
+
+ <section><title>Die Legende</title>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_legend.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_legend.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Legende</phrase> </textobject>
+ </inlinemediaobject>
+ </para>
+ <para>
+ Die Legende bietet eine Übersicht über die Ebenen der Karte.
+ Ebenen die weiter oben in der Legende stehen sind
+ ``näher'' zum Benutzer.
+ Falls eine Ebene Klassifizierung unterstützt (derzeit haben
+ nur Shape-Ebenen haben diese Eigenschaft) so werden die Gruppen
+ der Klassifikation für jede Ebene dargestellt.
+ Die Eigenschaften für jede Gruppe werden auch als kleine Grafiken
+ dargestellt. Polygon-Ebenen werden als Rechtecke dargestellt,
+ Linoen als Kurven und Punkte als Kreise.
+ </para>
+ <para>
+ Am oberen Rand der Legende ist eine Werkzeugleiste welche einen schnellen
+ Zugriff auf einige der Komanndos des Menüs
+ <menuchoice><guimenu>Map</guimenu></menuchoice>
+ gestattet.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Das Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_totop.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_totop.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Auf die oberste Ebene bewegen</phrase> </textobject>
+ </inlinemediaobject> bewegt die selektierte Ebene auf der Karte
+ nach ganz oben.
+ </para>
+ </listitem>
+ <listitem>
+
+ <para>
+ Das Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_moveup.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_moveup.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Eine Ebene nach oben bewegen</phrase> </textobject>
+ </inlinemediaobject> bewegt die selektierte Ebene um einen
+ Schritt nach oben.
+ </para>
+ </listitem>
+ <listitem>
+
+ <para>
+ Das Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_movedown.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_movedown.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Eine Ebene nach unten bewegen</phrase> </textobject>
+ </inlinemediaobject> bewegt die selektierte Ebene um einen Schritt
+ nach unten.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Das Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_tobottom.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_tobottom.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Auf die unterste Ebene bewegen</phrase> </textobject>
+ </inlinemediaobject> bewegt die selektierte Ebene auf
+ der Karte nach ganz unten.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Das Sichtbarkeits-Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_visible.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_visible.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Sichtbar</phrase> </textobject>
+ </inlinemediaobject> sorgt dafür, dass eine vorher nicht sichtbare
+ Ebene nun wieder in der Karte dargestellt wird.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Das Unsichtbar-Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_invisible.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_invisible.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Unsichtbar</phrase> </textobject>
+ </inlinemediaobject> versteckt die aktuell
+ selektierte Ebene auf der Karte.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Das Eigenschaften-Werkzeug
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_props.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_props.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Eigenschaften</phrase> </textobject>
+ </inlinemediaobject> startet den Eigenschaften-Dialog für die
+ aktuelle Ebene.
+ Ein Doppel-Klick auf eine Ebene startet ebenfalls diesen Dialog.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Die am häufigsten benötigten Aktionen zu den Ebenen sind
+ über ein Popup-Menü erreichbar. Es erscheint wenn Sie
+ mit der Maus über einer Ebene stehen und die rechten
+ Maustaste betätigen.
+ </para>
+
+ <para>
+ <figure>
+ <title>Popup Menü für Ebenen</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/3_5_popup_menu.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/3_5_popup_menu.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ <para>
+ Am unteren Rand der Legende befindet sich
+ die Maßstabsanzeige. Sie ist immer dann zu sehen wenn
+ für die Karte eine Projektion gesetzt ist und mindestens
+ eine Ebene vorhanden ist.
+ </para>
+ </section>
+
+ <section><title>Exportieren</title>
+ <para>
+ Auf dem Betriebssystem MS Windows können Karten im Enhanced Metafile Format
+ (<varname>.wmf</varname>)
+ über
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Export</guimenuitem>
+ </menuchoice> erstellt werden um sie in Reports,
+ Präsentationen oder weitergehenden Bearbeitungen zu verwenden.
+ Die aktuelle Kartenansicht, Legende und, falls verfügbar,
+ Maßstabsanzeige werden dafür exportiert.
+ Auf anderen Plattformen steht dies nicht zur
+ Verfügung.
+ Wählt man diesen Menüpunkt an so wird ein
+ Dateiauswahldialog für die zu erstellende Exportdatei
+ geöffnet.
+ </para>
+ </section>
+
+ <section><title>Drucken</title>
+ <para>
+ Eine Karte wird über
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Drucken</guimenuitem>
+ </menuchoice> ausgedruckt. Die aktuelle Kartenansicht, Legende und,
+ falls vorhanden, die Maßstabsanzeige werden gedruckt.
+ Es wird ein Standard-Druckdialog geöffnet der die Konfiguration
+ des Druckers gestattet. Dieser Druckdialog unterscheidet sich je
+ nachdem auf welcher Plattform Thuban ausgeführt wird.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Ebenen Management</title>
+ <para>
+ </para>
+
+ <section><title>Typen von Ebenen</title>
+ <para>
+ Thuban unterstützt 3 Typen von Ebenen:
+ Shape-Ebenen, Datenbank-Ebenen und Bild-Ebenen.
+ Shape-Ebenen bestehen aus vektor-basierten Objekten mit
+ geo-referenzierten Koordinaten.
+ Es werden drei Shape-Typen unterstützt:
+ Polygone, Linien und Punkte.
+ Datenbank-Ebenen sind den Shape-Ebenen ähnlich und unterscheiden
+ sich darin, dass die Daten aus einer Datenbank geholt werden
+ anstatt direkt vom Dateisystem.
+ Bild-Ebenen können im Prinzip alle von GDAL unterstützten Dateiformate
+ sein. GDAL ist eine externe Bibliothek und steht für
+ Geo-spatial Data Abstraction Library.
+ Das Bild muss Informationen zu seiner geographische Lage und
+ Ausdenung beinhalten, entweder direkt in die Datei eingebettet
+ oder als separate Datei im selben Verzeichnis wie die Bild-Datei.
+ GeoTIFF Dateien funktionieren sehr gut mit Thuban und sind
+ speziell als Bildebenen für Bild-Ebenen bei Geographischen
+ Informationssystemen geeignet.
+ </para>
+ <para>
+ Alle Aktionen im Menü
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ </menuchoice> beziehen sich auf die in der Legende aktuell
+ ausgewählten Ebene.
+ </para>
+ </section>
+
+ <section><title>Eigenschaften</title>
+ <para>
+ Um die Eigenschaften einer Ebene anzusehen muss zunächst eine Ebene
+ in der Legende selektiert werden.
+ Die Menüoption
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Eigenschaften</guimenuitem>
+ </menuchoice> öffnet einen Dialog zu den Eigenschaften
+ der Ebene.
+ Alle Ebenen haben einen Titel der hier entsprechend geändert werden kann.
+ Der Typ der Ebene ist ebenfalls ersichtlich.
+ Handelt es sich um einen Shape-Typ (Polygon, Linie, Punkt) so
+ wird eine Tabelle für Klassifizierung dargestellt.
+ Bildebenen haben keineweiteren Eigenschaften als
+ den Titel und Typ.
+ </para>
+ <para>
+ <figure>
+ <title>Eigenschaften Fenster</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/4_2_layer_properties.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/4_2_layer_properties.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ <figure>
+ <title>Eigenschaften Fenster</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/4_2_raster_layer_properties.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/4_2_raster_layer_properties.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ </section>
+
+ <section><title>Sichtbarkeit</title>
+ <para>
+ Manchmal ist es nicht erwünscht alle Ebenen gleichzeitig anzuzeigen.
+ Einige Ebenen könnten etwas länger für den Aufbau brauchen, was
+ z.B. störend bei schneller Navigation ist.
+ Jede Ebene kann einzeln an- oder ausgeschaltet werden mit
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Zeigen</guimenuitem>
+ </menuchoice>
+ bzw.
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Verstecken</guimenuitem>
+ </menuchoice>.
+ </para>
+ </section>
+
+ <section><title>Duplizierung</title>
+ <para>
+ Ebenen mit allen Eigenschaften inklusive Klassifikation
+ können dupliziert werden mit
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Duplizieren</guimenuitem>
+ </menuchoice>. Die Duplizierung von Ebenen ist sinnvoll
+ z.B. wenn eine Ebene auf verschiedene Weise modelliert werden
+ soll. Obwohl sich die Ebenen direkt überlagern ist es
+ durch sinnvolle Einstellung der Shape Eigenschaften möglich
+ mehrer Aspekte gleichzeitig zu visualisieren.
+ Beispielsweise kann eine Kopie einer Strassen-Ebene
+ bezüglich der Länge klassifiziert sein und eine
+ weitere Kopie bezüglich Strassen-Typ.
+ Wenn dann die Länge durch Farbe und der Typ durch Linienbreite
+ gesetzt wird, dann ist es möglich beide Eigenschaften zu
+ visualisieren indem die Kopie für den Typ über die Kopie mit
+ der Länge gelegt wird.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Ebenen-Klassifizierung</title>
+ <para>
+ Die Klassifizierung einer Ebene bedeutet das zuordnen von
+ Zeichenvorschriften zu Shape-Gruppen basierend auf deren Attributen
+ die in zur Ebene gehörenden Tabelle gespeichert sind.
+ Es können daher auch nur Shape-Ebenen klassifiziert werden und
+ keine Bild-Ebenen.
+ </para>
+ <para>
+ Eine Klassifizierung besteht aus mehreren Grupppen. Jede Gruppe
+ hat einen einzelnen Wert oder einen Wertebereich auf den hin
+ verglichen wird. Ausserdem hat jede Gruppe eine Zeichenvorschrift
+ welche bestimmt wie die zugehörigen Shapes dargestellt werden
+ sollen.
+ Der Anwender gibt an welches Feld der Tabelle für Klassifizierung
+ verwendet werden soll. Wird die Karte dann gezeichnet so
+ wird für jedes Shape der entsprechende Wert aus der Tabelle
+ geholt und mit den definierten Gruppen-Wertebereichen
+ verglichen. Es werden dann die Zeichenvorschriften
+ derjenigen Gruppe benutzt, welche als erstes beim Vergleich
+ passte.
+ Dies gestattet es einen visuellen Eindruck z.B.
+ der räumlichen Verteilung von Objekten mit
+ bestimmten Eigenschaften zu erhalten.
+ </para>
+ <para>
+ Eine Ebene hat grundsätzlich eine Klassifizierung.
+ Wird zur Karte eine neue Ebene hinzugefügt,
+ wird sie mit einer vordefinierten Klassifizierung
+ versehen. Diese besteht nur aus der einen Gruppe DEFAULT.
+ Diese Gruppe kann man nicht entfernen, lässt sich aber
+ verstecken (siehe unten).
+ Jedes Shape der Ebene, unabhängig von dessen Attributen, wird
+ diese Gruppe zugeordnet, falls nicht vorher eine andere passt.
+ </para>
+
+ <section><title>Klassifizierung bearbeiten</title>
+ <para>
+ Die Klassifizierung für eine Ebene wird über den Eigenschaftendialog
+ bearbeitet
+ (<menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Eigenschaften</guimenuitem>
+ </menuchoice>). Das Feld für die Klassifizierung der Ebene kann ugesetzt sein.
+ In diesem Fall wird die Gruppe DEFAULT als Klassifizierung eingesetzt.
+ Solange kein Feld gesetzt wird kann keine weiter Gruppe zur
+ Klassifizierung hinzugefügt werden.
+ Es muss also zunächst ein Feld ausgewählt werden. Dann können
+ weitere Gruppen mit dem Knopf
+ <guibutton>Hinzufügen</guibutton> in die Klassifizierung aufgenommen
+ werden.
+ </para>
+ <para>
+ Um die Änderungen auf die Karte anzuwenden kann der Benutzer
+ entweder <guibutton>Anwenden</guibutton> oder
+ <guibutton>OK</guibutton> verwenden.
+ <guibutton>Anwenden</guibutton> schliesst dabei den Dialog
+ nicht, sondern gestattet es, die gemachten Änderungen auf der
+ Karte als Voransicht zu sehen.
+ <guibutton>Zurücksetzen</guibutton> setzt die zuletzt angewendete
+ Klassifikation zurück.
+ <guibutton>OK</guibutton> wendet die Änderungen an
+ und schliesst den Dialog. Dann können die Änderungen
+ nicht mehr zurückgenommen werden.
+ <guibutton>Schliessen</guibutton> beendet den Dialog.
+ Alle Änderungen, die nicht mit <guibutton>Anwenden</guibutton> auf
+ die Karte gebracht wurden, werden verworfen.
+ </para>
+ <para>
+ <figure>
+ <title>Eigenschaften Fenster</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_classification.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_classification.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Die Reihenfolge der Gruppen in der klassifizierung ist
+ von Bedeutung. Eine Ausnahme bildet die Gruppe DEFAULT,
+ welche immer ganz oben verbleibt.
+ Werden die Shapes den Gruppen zugeordnet, so beginnt
+ der Vergleich mit der ersten Gruppe nach DEFAULT und dann
+ absteigend.
+ Der Vergleich endet sobald eine Gruppe für das Shape passt.
+ Mit <guibutton>Eine Ebene nach oben bewegen</guibutton> und
+ <guibutton>Eine Ebene nach unten bewegen</guibutton>
+ wird die Reihenfolge der Gruppen geändert.
+ Die Gruppe DEFAULT wird uaf alle Shapes angewandt die
+ auf keine der anderen Gruppen passssen.
+ </para>
+ <section><title>Sichtbar</title>
+ <para>
+ Die Spalte Sichtbar beinhaltet Ankreuzfelder mit denen
+ bestimmt werden kann ob die Gruppen auch in der
+ Legende dargestellt werden sollen.
+ Das ist zum Beispiel hilfreich wenn die Gruppen alle
+ Shapes abdecken und daher die Gruppe DEFAULT nicht
+ in der Legende bzw. im Ausdruck auftauchen soll.
+ </para>
+ </section>
+ <section><title>Symbole</title>
+ <para>
+ Jeder Shape-Typ hat seinen eigenen Symbol-Typ.
+ Thuban unterstützt 3 Shape-Typen: Polygone, Linien und Punkte.
+ Polygone und Punkte haben eine Rand- und Füllfarbe, Linien
+ haben nur eine Linienfarbe.
+ zu jeder Gruppe gehören Symbol-Eigenschaften.
+ Um diese zu bearbeiten, kann man entweder einen Doppelclick
+ auf das Symbol machen oder die entsprechende Gruppe
+ selektieren und dann den Knopf
+ <guibutton>Symbol bearbeiten</guibutton> verwenden.
+ </para>
+ </section>
+ <section><title>Wert</title>
+ <para>
+ Die Spalte Wert enthält die Werte auf die die Shapes
+ verglichen werden wenn die Karte gezeichnet wird.
+ Die Art der Angaben in diesen Feldern hängt vom
+ Typ der Daten des Klassifizierungs-Feldes.
+ </para>
+ <para>
+ Ist das Feld vom Typ Text, sind beliebige Eingaben erlaubt.
+ Der Text wird buchstabenweise mit dem Wert des Shape-Attributes
+ verglichen. Gross-Kleinschreibung wird dabei berücksichtigt.
+ Ist das Feld vom Typ Integer, sind alle ganzen Zahlen
+ erlaubt. Darüber hinaus können auch mit spezieller Syntax
+ Bereiche angegeben werden.
+ Ein Bereich von <varname>start</varname> bis
+ <varname>ende</varname> inklusive der Grenzen wird so
+ eingegeben: <literal>[start;ende]</literal>.
+ Der Bereich ohne die Grnezen wird so angegeben:
+ <literal>]start;ende[</literal>. Bereich können auch
+ Unendlich als Wert benutzen: <literal>[-oo;oo]</literal>.
+ Der Feld-Typ kann auch Dezimal sein. Dann können beliebeige
+ rationale Zahlen verwendet werden.
+ </para>
+ </section>
+ <section><title>Label</title>
+ <para>
+
+
+ als Voreinstellung wird als Label für die Gruppe in der
+ Legende der Wert verwendet. Es kann aber auch ein spezieller
+ Label angegeben werden.
+ </para>
+ </section>
+ </section>
+
+ <section><title>Erzeuge Klassifikation</title>
+ <para>
+ <figure>
+ <title>Erzeuge Klasse</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_3_genclass.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_3_genclass.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Das manuelle erstellen eine Klassifikation
+ kann anstrengend werden.
+ Thuban bietet hier die Möglichkeit, Klassikationen
+ automatisch, aber unter Kontrolle des Benutzers, zu
+ erstellen.
+ Clicked man auf <guibutton>Erzeuge Klasse</guibutton>
+ so wird der Dialog <varname>Erzeuge Klassifikationn</varname>
+ geöffnet.
+ Unter dem Aufklappmenü <varname>Erzeuge</varname> finden sich
+ in der Regel drei unterschiedliche Arten für die
+ Erzeugung von Klassifikationen:
+ Eindeutige Werte, Gleichförmige Verteilung und Quantile.
+ Einige Optionen sind nicht verfügbar wenn der Datentyp
+ des Feldes es nicht unterstützt.
+ So macht beispielsweise <varname>Gleichförmige Verteilung</varname>
+ keinen Sinn bei Text-Feldern.
+ </para>
+ <para>
+ In jedem Fall muss bei der Erzeugung einer Klassifizierung
+ ein Farbschema ausgewählt werden.
+ Thuban bietet einige verschiedene Farb-Schemata die dann bestimmen
+ wie sich Gruppeneigenschaften über die Klassifizierung ändern.
+ Es mag gewünscht sein, dass nur bestimmte Eigenschaften
+ sich über die Klassifizierung ändern.
+ Ist der Shape-Typ Polygon oder Punkt, so die Option
+ <guibutton>Rahmenfarbe festlegen</guibutton> verfügbar.
+ Diese erlaubt es, eine feste Rahmenfarbe für alle
+ Gruppen der Klassifizierung festzulegen.
+ Es ist ebenfalls möglich ein benutzerdefiniertes Farbschema
+ zu erstellen.
+ Wählt man diese Option aus, werden zwei Symbole
+ dargestellt: das linke Symbol hat die Eigenschaften für
+ die erste Gruppe, das rechte für die letzte Gruppe.
+ Thuban interpoliert dann zwischen diesen beiden um die
+ Eigenschaften für die enderen Gruppen zu erstellen.
+ <figure>
+ <title>Benutzerdefiniertes Farbschema</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_custom_ramp.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_custom_ramp.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Die Option Eindeutige Werte erlaubt es, spezielle Werte
+ auszuwählen die in der Tabelle vorkommen.
+ Clickt man <guibutton>Aus Tabelle holen</guibutton>
+ so wird die Tabelle nach allen vorkommenden Werten
+ durchsucht und diese in der Liste auf der linken Seite dargestellt.
+ Beide Listen für eine schnellere Suche sortiert
+ oder umgedreht werden.
+ Die Klassifizierung die dann erzeugt wird
+ wird dieselbe Sortierung wie die rechte Liste haben.
+ <figure>
+ <title>Eindeutuige Werte</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_unique_values.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_unique_values.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Die Option Gleichförmige Verteilung erzeugt die angegebene
+ Anzahl von Gruppen mit Bereichen wobei alle Bereiche
+ das gleiche Intervall haben.
+ Minimum und Maximum hierfür können automatisch aus der Tabelle
+ ermittelt werden indem die Option
+ <guibutton>Aus Tabelle holen</guibutton> verwendet wird.
+ Die Stufen bestimmen die Grösse des Intervalls.
+ Ändert man diesen Wert, wird automatisch neu berechnet
+ wie viele Gruppen nun passend sind.
+ <figure>
+ <title>Gleichförmige Verteilung</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_uniform_dist.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_uniform_dist.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Die Option Quantile erzeugt Bereiche anhand der Anzahl Elemente in
+ der Tabelle.
+ Beispielsweise werden durch die Wahl von fünf Gruppen
+ entsprechend fünf Gruppen mit passenden Bereichen erstellt,
+ so dass 20% der Tabellendaten in jeder Gruppe enthalten sind.
+ Ist es nicht möglich exakte Gruppierungen zu erzeugen,
+ sow wird Thuban Warnung mitteilen aber die Aktion fortführen.
+ <figure>
+ <title>Quantile</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_quantiles.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_quantiles.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Projektions-Management</title>
+ <para>
+ Projektionen bestimmen wie geographische Daten auf dem
+ Bildschirm dargestellt werden.
+ Werden mehrere Ebenen in Thuban geladen bei denen die
+ geographischen Daten in verschiedenen Projektionssystemen
+ vorliegen, so muss jeder Ebene die entsprechende Projektion
+ zugeordnet sein. Ebenso muss eine Projektion für die Karte
+ angegeben werden.
+ Dies kann die gleiche wie die der Ebenen sein oder eine
+ andere Projektion wobei dann die Ebenen entsprechend
+ umprojeziert werden.
+ Die Projektion der Karte wird über
+ <menuchoice>
+ <guimenu>Karte</guimenu>
+ <guimenuitem>Projektion</guimenuitem>
+ </menuchoice> und die Projektionen für die Ebenen über
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Projektion</guimenuitem>
+ </menuchoice> gesetzt.
+ <figure>
+ <title>Projektionsauswahl-Fenster</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/6_projection.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/6_projection.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Thuban kommt mit eine Beispiel-Sammlung von Projektionen sowie
+ dem von der EPSG (European Petroleum Survey Group) Satz. Dieser
+ recht umfangreiche Satz wird nur angezeigt wenn er durch das entsprechende
+ Wahlfeld eingeschaltet wurde.
+ Der Satz besteht aus zwei Gruppen, die Liste der veralteten Projektionen
+ enthält diejenigen Projektionen die eine EPSG Nummer haben aber
+ in der aktuellen EPSG Datenbank nicht mehr enthalten sind.
+ </para>
+ <para>
+ Ein Benutzer kann neue Projektionen definieren und sie für zukünftige
+ Thuban Sitzungen zugängig machen. Sie können auch exportiert
+ und importiert werden, so dass spezielle Projektionen
+ leicht weitergegeben werden können.
+ </para>
+ <section><title>Eine Projektion auswählen</title>
+ <para>
+ Die verfügbaren Projektionen sind link aufgelistet.
+ Hat die Ebene oder Karte bereits eine Projektion,
+ so ist diese zunächst hervorgehoben und trägt den Hinweis
+ <varname>(aktuell)</varname>. Wird
+ <varname><Keine></varname> ausgwählt, so wird Thuban die Daten
+ dirket verwenden wie sie in den Quellen vorkommen und keine
+ Umprojezierung vornehmen.
+ </para>
+ </section>
+ <section><title>Eine Projektion bearbeiten</title>
+ <para>
+ Immer wenn eine Projektion aus der Liste ausgwählt wird, dann
+ werden deren konkrete Eigenschaften rechts dargestellt.
+ Diese Eigenschaften können geändert werden und die Änderungen
+ in der Projektion über <guibutton>Aktualisieren</guibutton>
+ gespeichert werden.
+ Es können ausschliesslich Projektionen aktualisiert
+ werden, die aus einer Datei kommen.
+ Wenn also die Projektion der aktuellen Ebene angewählt ist, so
+ ist die Aktion <guibutton>Aktualisieren</guibutton> deaktiviert.
+ <guibutton>Hinzufügen zur Liste</guibutton> fügt die Projektion
+ an die Liste der verfügbaren Projektionen an und macht sie so
+ auch in zukünftigen Thuban Sitzungen verfügbar.
+ Mit <guibutton>Neu</guibutton> wird eine neue, leere Projektion
+ erzeugt.
+ Die Aktion <guibutton>Entfernen</guibutton> löscht eine
+ Projektion dauerhaft aus der Liste.
+ </para>
+ <para>
+ Um eine Projektion auf die Karte anzuwenden kann man
+ <guibutton>Anwenden</guibutton> oder <guibutton>OK</guibutton>
+ benutzen.
+ <guibutton>Anwenden</guibutton> schliesst den Dialog nicht
+ und erlaubt es so, die Änderung auf der Karte zunächst zu begutachten.
+ <guibutton>Zurücksetzen</guibutton> macht die zuletzt gemachte
+ Änderung wieder rückgängig.
+ <guibutton>OK</guibutton> aktiviert die gemachten Änderung und
+ schliesst den Dialog.Danach kann man diese Änderung nicht mehr
+ rückgängig machen.
+ <guibutton>Schliessen</guibutton> beendet den Dialog.
+ Wurde bis dahin keine Projektion mit
+ <guibutton>Anwenden</guibutton> ausprobiert, so wird sie auch
+ nicht auf die Karte übertragen.
+ </para>
+ </section>
+ <section><title>Projektionen Importieren/Exportieren</title>
+ <para>
+ Projektionen die in der Liste verfügbaren Projektionen auftauchen
+ können in eine Datei exportiert werden.
+ Nach der Auswahl einer oder mehrerer Projektionen wird nach betätigen von
+ <guibutton>Export</guibutton> ein entsprechender
+ Dateiauswahldialog gestartet.
+ Die Datei kann dann z.B. an andere Thuban-Anwender weitergegeben
+ werden.
+ Um eine solche Datei zu importieren verwendet man die Aktion
+ <guibutton>Import</guibutton>.
+ Die importierten Projektionen werden zur Liste verfügbarer
+ Projektionen zur sofortigen oder späteren Verwendung hinzugefügt.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Tabellen-Management</title>
+ <para>
+ Thuban unterscheidet zwei unterschiedliche Tabellen-Typen:
+ Attributtabellen (welche zu einer Ebene gehört) sowie normale
+ Datentabellen.
+ Beide bieten die gleiche allgemeine Funktionalität mit dem
+ einzigen Unterschied, dass Aktionen auf einer Attributtabelle
+ die Kartendarstellung ändern können.
+ </para>
+
+ <section><title>Tabellen-Ansicht</title>
+ <para>
+ <figure>
+ <title>Tabellen-Ansicht</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/7_1_table_view.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/7_1_table_view.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Thuban stellt einen Standard-Dialog für die Anzeige einer Tabelle
+ zur Verfügung. Diese Aansicht hat 5 Elemente:Titel, Selektion,
+ das Tabellenraster, Exportfunktionen und die Statuszeile.
+ </para>
+ <para>
+ Die Titelzeile identifiziert die Tabelle mit ihrem Namen.
+ </para>
+ <para>
+ Die Selektionsbox erlaubt es dem Benutzer einfache Analysen auf den Daten
+ durch Vergleiche durchzuführen: Die erste Auswahl ist ein Feldbezeichner
+ der Tabelle, die zweite Auswahl bestimmt den Typ des Vergleichs.
+ Die dritte Auswahl kann entweder ein bestimmter Wert (interpretiert
+ als Zahl oder als Zeichenkette abhängig vom Typ des ersten Feldes)
+ oder ein zweiter Feldbezeichner sein.
+ D.h. man kann Analysen durchführen wie alle Einträge auswählen bei
+ denen <literal>bevoelkerung > 10000</literal> oder
+ <literal>pkw_pro_einwohner < fahrraeder_pro_einwohner</literal>
+ (beachten Sie, dass die Namen nur exemplarisch sind, dBase Dateien
+ erlauben nur Bezeichner mit einer maximalen Länge von 11 Zeichen).
+
+ Selektionen können kombiniert werden. Entweder bezieht sich
+ die Selektion auf die zuvor selektierten Einträge oder man kann
+ eine bestehende Selektion erweitern. Voreingestellt ist
+ einersetzen der bisherigen Selektion.
+ </para>
+ <para>
+ Das Tabellenraster zeigt den Inhalt der Tabelle (pro Zeile ein Eintrag).
+ Selektionen sind hervorgehoben. Die Grösse der Zeiken und Spalten kann
+ verändert werden.
+ </para>
+ <para>
+ Der Inhalt einer Tabelle kann in eine Datei exportiert werden,
+ entweder im dBase format (DBF) oder als kommaseparierte Werte
+ (CSV). Der.
+ <guibutton>Export</guibutton> Knopf startet einen Dialog
+ zur Angabe des Pfades und des Namens der Datei.
+ Der Export-Typ wird durch die Namenserwiterung spezifiziert
+ (entweder .dbf oder .csv).
+
+ Der Knopf <guibutton>Exportiere Selektion</guibutton> funktioniert
+ ähnlich, exportiert aber nur die aktuelle Selektion.
+
+ Der <guibutton>Schliessen</guibutton> Knopf schliesst das
+ Fenster mit der Tabellenansicht. Dies ist nicht zu verwechseln mit
+ dem Menüpunkt
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Schliessen</guimenuitem>
+ </menuchoice> welcher die Tabelle aus Thuban entfernt.
+ </para>
+ <para>
+ Die Statuszeile zeigt einige statistische Informationen zu
+ der Tabelle sowie zu Selektionsergebnisse an.
+ </para>
+ </section>
+
+ <section><title>Allgemeine Funktionalität (Menü Tabelle)</title>
+ <para>
+ Die allgemeinen Funktionen wirken sich auf alle geöffneten Tabellen
+ aus. Attributtabellen werden wie normale Tabellen behandelt (mit der
+ Ausnahme dass diese nicht geschlossen werden können).
+ </para>
+ <section><title>Öffnen</title>
+ <para>
+ Der Menüpunkt
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Öffnen</guimenuitem>
+ </menuchoice>
+ startet einen Dateiselektionsdialog für die Auswahl
+ einer dBase-Datei. Diese wird als nur-lesbar in Thuban
+ geladen.
+ Mit <guibutton>OK</guibutton> wird die ausgewählte Datei
+ geladen und eine entsprechende Tabellenansicht geöffnet.
+ </para>
+ </section>
+
+ <section><title>Schliessen</title>
+ <para>
+ Der Menüpunkt
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Schliessen</guimenuitem>
+ </menuchoice>
+ startet einen Dialog welcher alle derzeit geöffneten Datentabellen
+ (die geladen wurden über
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Öffnen</guimenuitem>
+ </menuchoice>).
+ Die gewählten Tabellen werden nach Bestätigung aus Thuban
+ entfernt.
+ Da die Tabellen als nur-lesend geöffnet wurden, wird
+ der Inhalt der Tabellen nicht verändert.
+
+ Sämtliche offenen Tabellenansichten für diese
+ Tabellen werden ebenfalls geschlossen.
+
+ Tabellen die bei Verknüpfungen verwendet werden
+ können nicht geschlossen werden.
+ </para>
+ </section>
+
+ <section><title>Umbenennen</title>
+ <para>
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Umbenennen</guimenuitem>
+ </menuchoice> ändert den Tabellentitel.
+ </para>
+ </section>
+
+ <section><title>Anzeigen</title>
+ <para>
+ Der Menüpunkt
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Anzeigen</guimenuitem>
+ </menuchoice>
+ öffnet einen Dialog mit der Liste der verfügbaren
+ Tabellen (explizit geladene Tabellen, Attributtabellen,
+ Ergebnisse aus Verknüpfungen).
+ Die ausgewählten Tabellen werden nach der
+ Bestätigung mit
+ <guibutton>OK</guibutton> in Tabellenansichten dargestellt.
+ </para>
+ </section>
+
+ <section><title>Verbinden</title>
+ <para>
+ <figure>
+ <title>Verbinde Tabellen</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/7_2_5_join.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/7_2_5_join.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Der Menüpunkt
+ <menuchoice>
+ <guimenu>Tabelle</guimenu>
+ <guimenuitem>Verbinden</guimenuitem>
+ </menuchoice>
+ startet einen Dialog für die Angabe der beiden Tabellen die
+ verbunden werdn sollen. Das Ergebnis der Verbindung ist eine
+ neue Tabelle mit der Bezeichnung
+ 'Join of "linke Tabelle" and "rechte Tabelle"'.
+
+ Der Dialog erlaubt es die beiden zu verbindenden Tabellen sowie
+ die beiden Felder anzugeben über die die Verbindung hergestellt
+ werden soll. Als Voreinstellung beinhaltet die neue Tabelle
+ nur die Einträge für die entsprechende Übereinstimmungen
+ vorlagen.
+
+ Wollen Sie die Einträge der linken Tabelle erhalten, so können
+ Sie eine äussere Verbindung erstellen. Die Felder der rechten
+ Tabelle für Einträge ohne Übereinstimmung werden in diesem
+ Fall aufgefüllt mit dem Wert <varname>None</varname>.
+ </para>
+ </section>
+
+ </section>
+ <section><title>Attribut-Tabellen</title>
+ <para>
+ Um klarer zwischen den beiden Tabellen-Typen (Daten und Attribute) zu
+ unterscheiden, bietet Thuban die Funktionalität für die Attribut-Tabellen
+ unter dem Menü
+ <menuchoice><guimenu>Ebene</guimenu></menuchoice> an.
+ </para>
+
+ <section><title>Zeige Tabelle</title>
+ <para>
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Zeige Tabelle</guimenuitem>
+ </menuchoice>
+ öffnet die Attribut-Tabelle für die aktuell aktive Ebene in
+ einer Tabellenansicht.
+
+ Eine zusätzliche Funktionalität bei diesen Tabellenansichten
+ ist, dass bei Selektionen die korrespondierenden Objekte
+ auf der Karte unmittelbar hervorgehoben werden.
+ </para>
+ </section>
+
+ <section><title>Verbinde Tabelle</title>
+ <para>
+ Anders als beim Verbinden wie oben beschrieben
+ erzeugt dieses Verbinden keine neue Tabelle.
+ Die Attributtabelle der aktiven Ebene stelllt die linke
+ Tabelle. Die anderen Tabellen werden an diese angebunden.
+ Das Ergebnis dieser Verbindung steht z.B. für Klassifizierungen
+ zur Verfügung.
+
+ Daraus folgt auch, dass die Verbindung niemals weniger
+ Einträge haben als die ursprüngliche Attributtabelle.
+ Der Benutzer wird gewarnt, falls die recht Tabelle dies
+ nicht erfüllen kann. In so einem Fall muss eine
+ äussere Verbindung durchgeführt werden.
+ </para>
+ </section>
+
+ <section><title>Tabellen-Verbindung lösen</title>
+ <para>
+ Wie schon erwähnt kann eine Tabelle nicht geschlossen
+ werden wenn sie noch bei einer Verbindung verwendet wird.
+ Tabellen die neu aus der Verbindung zweier normaler Tabellen
+ entstanden sind, können ohne weiteres gelöst werden.
+ Dies gilt jedoch nicht für Attributtabellen.
+
+ Also müssen Attributtabellen explizit gelöst werden.
+ Dazu wird das Kommando
+ <menuchoice>
+ <guimenu>Ebene</guimenu>
+ <guimenuitem>Verbindungen lösen</guimenuitem>
+ </menuchoice>
+ verwendet: Die jeweils zuletzt gemachte Verbindung wird
+ gelöst.
+ </para>
+ </section>
+ </section>
+ </chapter>
+
+ <chapter><title>Erweiterungen</title>
+ <para>
+ Thuban ist so konstruiert, dass es leicht
+ erwiterbar ist. Der Begriff Erweiterungen wird
+ als allgemeine Bezeichnung für alles verwendet, was Thuban
+ erweitert.
+ Diese Kapitel gibt eine Einführung in verschiedene Möglichkeiten
+ weitere Funktionalität zu Thuban hinzuzufügen, entweder
+ eigene Entwicklungen oder die von Dritten.
+ </para>
+
+ <section><title>Eigene Erweiterungen über thubanstart.py</title>
+ <para>
+ iNachdem Thuban zum ersten mal gestartet wurde, wird
+ ein Verzeichnis .thuban im Heimatverzeichnis des
+ Benutzers erzeugt.
+ Dort kann die Datei thubanstart.py angelegt werden,
+ die dann beim Start von Thuban importiert wird.
+ Es ist empfehlenswert ausschliesslich import-Kommandos
+ in dieser Datei aufzunehmen und den eigentlichen
+ Programmcode separat zu halten.
+ </para>
+ <para>
+ Die Module die importiert werden müssen entweder
+ über die Pfade in Umgebungsvariablen
+ PYTHONPATH gefunden werden oder direkt
+ im .thuban-Verzeichnis abgelegt sein.
+ </para>
+ <para>
+ Als Beispiel kann man die Datei
+ examples/simple_extensions/hello_world.py
+ aus dem Thuban Quelltext in das persönliche .thuban-Verzeichnis
+ kopieren.
+ Nun kann das Kommando import hello_world in die Datei
+ thubanstart.py aufgenommen werden. Nach dem Start von Thuban
+ wird man dann ein zusätzliches Menü
+ <menuchoice><guimenu>Extensions</guimenu></menuchoice> vorfinden
+ in dem der Unterpunkt für die Hello-World Erweiterung
+ zu sehen ist. Wählt man diesen Punkt aus, so
+ wird die bekannte Hello-World Mitteilung ausgegeben.
+ </para>
+ </section>
+
+ <section><title>Im Thuban-Paket enthaltene Erweiterungen</title>
+ <para>
+ Die hier beschriebenen Erweiterungen sind Teil des Thuban-Paketes,
+ aber nicht automatisch aktiviert.
+ Sie befinden sich im Thuban Installations-Verzeichnis unter
+ <literal>Extensions/</literal>. Man aktiviert sie über
+ PYTHONPATH und import wie im obigen Abschnitt erklärt.
+ Stabile Erweiterungen tauchen unter dem Menü
+ <menuchoice><guimenu>Extensions</guimenu></menuchoice> auf
+ und solche die sich noch im experimentellen Stadium
+ befinden und daher unter Umständen nicht komplett
+ funktional unter
+ <menuchoice><guimenu>Experimental</guimenu></menuchoice>.
+ </para>
+
+ <section><title>Stabile Erweiterungen</title>
+ <para>
+ Diese Erweiterungen bieten zusätzliche Funktionalität
+ für Thuban die nicht in Kernanwendung integriert
+ ist. Es wird angenommen, dass keine bedeutenden
+ Fehler mehr enthalten sind.
+ </para>
+ <section><title>gns2shp</title>
+ <para>
+ Dieses Werkzeug konvertiert Daten des
+ Geospatial Names Server
+ (GNS, siehe <ulink url="http://www.nima.mil/gns"/>)
+ in das Shapefile-Format.
+ Die GNS Webseite bietet den Download die Informationen zu
+ benannten Orten nach Ländern gruppiert für alle Länder an.
+ Einzige Ausnahme sind die USA für welche die Daten in anderer
+ Form angeboten werden.
+ </para>
+ <para>
+ Wenn man einen Datensatz herunterlädt und auspackt so erhält
+ man eine Textdatei mit dem Anhang .txt.
+ Wählt man eine solche Textdatei via gns2shp aus, so
+ wird ein Shapefile mit dem selben Basisnamen
+ erzeugt und im gleichen Verzeichnis abgelegt.
+ Danach wird es automatisch in Thuban eingeladen.
+ Die Shapefile Dateien werden nicht automatisch
+ wieder gelöscht.
+ </para>
+ <para>
+ Das Modul gns2shp.py kann auch auf der Kommandozeile
+ verwendet werden, z.B. für Stapelverarbeitung.
+ </para>
+ <para>
+ Ein Beispiel (<literal>ls.txt</literal> für Liechtenstein)
+ befindet sich im Verzeichnis
+ <literal>Extensions/gns2shp/test</literal>.
+ </para>
+ </section>
+
+ <section><title>SVG Export</title>
+ <para>
+ Karte und Legende können separat in das Thuban-SVG-Format exportiert
+ werden.Die erzeugten Dateien entsprechen der
+ Scalable Vector Graphics (SVG) 1.1 Specification
+ und können von den meisten Vektorzeichenprogrammen gelesen
+ werden.
+ </para>
+ <para>
+ Ziel des SVG-Export ist es, den Beginn einer
+ Druck-Kette für Thuban-Karten anzubieten.
+ Für diesen Zweck enthalten die erzeugten Thuban-Karten-SVG Dateien
+ zusätzliche Informationen welche in einer Nachbearbeitung
+ verwendet werden können.
+ Typischerweise ist ein Vektorzeichenprogramm wesentlich
+ mächtiger bei der grafischen Ausgestaltung als eine
+ Geodaten-Betrachter; z.B. stehen viel mehr Symbole
+ und Fonts zur Verfügung.
+ Auch unterstützt dies den Anwender darin, aufgabenorientierte
+ Komponenten jweils sinnvoll auszunutzen.
+ Die Idee ist also, das Zeichenprogramm für die Druckvorbreitung
+ zu verwenden und nicht das GIS. Die zusätzlichen Informationen
+ die im Export-Format gespeichert werden ermöglichen es,
+ dass wenn sich nur einzelne Geo-Objekte ändern
+ das Layout und die Stile für die ganze Karte im Zeichenprogramm
+ beizubehalten.
+ </para>
+ <para>
+ Markus Rechtien hat den Prototyp dieser
+ Druckkette im Rahmen einer Diplomarbeit
+ entwickelt und validierte damit ein
+ Konzept von Bernhard Reiter.
+ Skripte für entsprechende Weiterverarbeitung
+ existieren für die Zeichenanwendung Skencil
+ (<ulink url="http://www.skencil.org"/>).
+ </para>
+ <para>
+ Technische Hinweise: die Namen der Ebenen werden
+ als Basis für IDs im SVG-Format verwendet.
+ Wenn man versucht, zwei Ebenen mit gleichem Namen
+ zu exportieren, dann tritt entsprechend ein Fehler auf.
+ Ändern Sie einfach den Namen einer Ebene und versuchen
+ Sie es erneut.
+ </para>
+ </section>
+ </section>
+
+ <section><title>Experimentelle Erweiterungen</title>
+ <para>
+ Die hier beschriebenen Funktionen sollten mit Vorsicht
+ verwendet werden, da sie nicht vollständig und/oder nicht
+ ausreichend getestet sind.
+ Trotzdem können sie in der Praxis schon recht hilfreich sein.
+ </para>
+ <para>
+ Interesse, diese Erweiterungen zu verbessern sollte
+ auch der Entwickler- und Benutzergemeinschaft
+ mitgeteilt werden.
+ </para>
+
+ <section><title>importAPR</title>
+ <para>
+ Dieses Kommando gestattet es, eine ESRI® ArcView® Projectdatei
+ zu laden (endet auf .apr) und für weitere Nutzung in Thuban
+ zu konvertieren.
+ Nach Auswahl der zu ladenden apr-Datei erscheint eine
+ Auswahlliste mit den enthaltenen Ansichten, falls mehr als
+ eine existiert.
+ Desweiteren wird der Session Infobaum um eine Repräsentation
+ der kompletten apr-Datei erweitert.
+ </para>
+ <para>
+ Die Legende von Thuban deckt nicht alle Elemente die von
+ ArcView® unterstützt werden ab.
+ Daher wird die Karte in Thuban anders aussehen.
+ Zudem ist das apr-Format proprietär und nicht offen dokumentiert.
+ Das bedeutet, dass die Interpretation auf
+ Reverse Engeneering und intelligentem Raten basiert.
+ </para>
+ <para>
+ Die Dateipfade innherhalb der apr-Datei passen unter
+ Umständen nicht und müssen ggf. manuell in der apr-Datei
+ mit einem Texteditor angepasst werden.
+ Die Pfade m:The paths are either absolute
+ or relative from where Thuban has been started.
+ </para>
+ <para>
+ A sample for the Iceland data is included as
+ <literal>Extensions/importAPR/samples/iceland.apr</literal>.
+ The file-paths are relative from the Thuban main directory.
+ </para>
+ </section>
+ </section>
+ </section>
+
+ <section><title>Writing simple extensions</title>
+ <para>
+ Writing an extension for Thuban basically means to
+ implement the extra functionality in Python with all of the
+ Thuban classes, methods and variables available.
+ </para>
+ <para>
+ All classes and their methods are documented in the source code
+ (see their doc-strings). Here is an example from
+ Thuban/Model/layer.py that describes some of the methods
+ of a Layer object:
+ </para>
+ <programlisting>
+ <![CDATA[
+class BaseLayer(TitledObject, Modifiable):
+
+ """Base class for the layers."""
+
+ def __init__(self, title, visible = True, projection = None):
+ """Initialize the layer.
+
+ title -- the title
+ visible -- boolean. If true the layer is visible.
+ """
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.visible = visible
+ self.projection = projection
+
+ def Visible(self):
+ """Return true if layer is visible"""
+ return self.visible
+
+ def SetVisible(self, visible):
+ """Set the layer's visibility."""
+ self.visible = visible
+ self.issue(LAYER_VISIBILITY_CHANGED, self)
+
+ def HasClassification(self):
+ """Determine if this layer support classifications."""
+...
+ ]]>
+ </programlisting>
+ <para>
+ This example intends to give you an impression of the
+ source-code-level documentation.
+ You have to make yourself familiar with
+ the Python programming language to understand some special
+ code elements.
+ </para>
+ <section><title>hello_world.py</title>
+ <para>
+ Traditionally, the first example should welcome the world.
+ Most of the code handles the frame for integrating a menu
+ item into Thuban while the actual raising of a message
+ is done in a single line.
+ </para>
+ <programlisting>
+ <![CDATA[
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend Thuban with a sample Hello World to demonstrate simple
+extensions.
+"""
+
+__version__ = '$Revision: 2627 $'
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+def hello_world_dialog(context):
+ """Just raise a simple dialog to greet the world.
+
+ context -- The Thuban context.
+ """
+ context.mainwindow.RunMessageBox(_('Hello World'), _('Hello World!'))
+
+
+# create a new command and register it
+registry.Add(Command('hello_world', _('Hello World'), hello_world_dialog,
+ helptext = _('Welcome everyone on this planet')))
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally bind the new command with an entry in the extensions menu
+extensions_menu.InsertItem('hello_world')
+ ]]>
+ </programlisting>
+ </section>
+ <section><title>Registering a Command</title>
+ <para>
+ Mainly, our new function has to be registered to the Thuban
+ framework in order to connect it to the menu. A registered
+ command can also be connected to e.g. a toolbar button.
+ </para>
+ <para>
+ The instances and classes for this are imported at the beginning.
+ Any code not inside a method or class is directly executed when
+ the source-code module is imported. Therefore, the second
+ part of this example consist of the plain statements to create a new
+ Command and to add it to the menu.
+ </para>
+ <para>
+ By convention, it looks for a menu registered as ``extensions'' to
+ insert the new command. If it does not exist yet, it gets created.
+ It is advisable to copy this code for any of your extensions.
+ </para>
+ </section>
+ <section><title>The Thuban context</title>
+ <para>
+ A registered command that is called, always receives the
+ Thuban context. This instance provides our method with
+ hook references to all important components of the Thuban
+ application.
+ </para>
+ <para>
+ In the example hello_world.py, our function uses the
+ mainwindow component which offers a method to raise a
+ message dialog. In total there are three hooks:
+ <itemizedlist>
+ <listitem>
+ <para>application:
+ This object is the instance of the Thuban Application class.
+ Except maybe for loading or savinf sessions, you will not
+ need this object for a simple extension.
+ See Thuban/UI/application.py for the API.
+ </para>
+ </listitem>
+ <listitem>
+ <para>session:
+ The instance of the current session. It manages the sessions'
+ map and tables. You can set and remove the map or tables.
+ In may also get the map object. However, you should know that
+ internally it is already prepared to handle many maps.
+ Therfore, currently you would always receive a list with exactlty
+ one element. In the future, if there are more than one map,
+ you will not know which one is the currently display one and
+ therefore you should use the mainwindow as hook to find
+ the currently displayed map.
+ See Thuban/Model/session.py for the API.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ mainwindow: The mainwindow object is central to manage various
+ GUI things such as the Legend sub-window. Most notably,
+ you get access to the canvas which is the window part where
+ the map is drawn. The canvas knows, which map it currently
+ draws and therefore you get the current map via
+ context.mainwindow.canvas.Map().
+ See Thuban/UI/mainwindow.py for the API.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+ </section>
+ </chapter>
+
+ <chapter><title>Trouble Shooting</title>
+ <para>
+ Here are a few problems that users have encountered when first using Thuban.
+ </para>
+ <para>
+
+ <itemizedlist>
+ <listitem>
+ <para>After adding two or more layers nothing is drawn in the map window.
+ </para>
+ <para>
+ This is probably because the layers have different projections. Projections
+ must be set on all layers and on the map itself if the layers' projections
+ are different.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Thuban crashes on startup with the error
+ <literal>NameError: global name 'False' is not defined</literal>.
+ </para>
+ <para>
+ <varname>True</varname> and <varname>False</varname> were only introduced
+ in Python 2.2.1. Thuban depends on at least Python 2.2.1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>After compiling Thuban, Thuban crashes with an error similar to
+ <literal>
+ ImportError: /usr/local//lib/thuban/Thuban/../Lib/wxproj.so: undefined symbol: __gxx_personality_v0
+ </literal>
+ </para>
+ <para>
+ Thuban depends on the wxWindows library. If Thuban is compiled with an
+ incompatible version of the compiler than wxWindows was compiled with
+ this error may occur. Try compiling with a different version of the
+ compiler.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ If an error occurs Thuban will display a dialog indicating the error
+ before closing. The text should be copied and reported to the
+ <ulink url="http://thuban.intevation.org/bugtracker.html">
+ Intevation bugtracker
+ </ulink>.
+ More information about the system is available from
+ <menuchoice><guimenu>Help</guimenu><guimenuitem>About</guimenuitem></menuchoice> box.
+ This should also be included in the bug report.
+ <figure>
+ <title>Error Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/8_int_error.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/8_int_error.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ </chapter>
+
+ <appendix><title>Supported Data Sources</title>
+ <para>
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Shapefile</term>
+ <listitem>
+ <para>
+ The Shapefile format has become a standard format for saving
+ geographic vector information. It supports polygons, lines, and
+ points.
+
+ <ulink url="http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf">
+ Technical Specification.
+ </ulink>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>dBase file</term>
+ <listitem>
+ <para>
+ dBase files are used to store the attributes for each layer. This
+ is closely associated with the Shapefile format. For detailed
+ specifications on the correct format of a dBase file used with
+ Thuban please see the Technical Specification for the Shapefile
+ format above.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>PostGIS</term>
+ <listitem>
+ <para>
+ PostGIS adds support for geographic objects to the PostgreSQL
+ object-relational database. Different layer types (as for Shapefiles)
+ are supported. <ulink url="http://postgis.refractions.net">PostGIS
+ Homepage</ulink>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Raster files</term>
+ <listitem>
+ <para>
+ Binding the GDAL library Thuban supports numerous raster file formats,
+ see <ulink url="http://www.remotesensing.org/gdal/formats_list.html">
+ GDAL format list</ulink> for details.</para>
+
+ <para>Most commonly used is the <emphasis>TIFF/GeoTIFF</emphasis>
+ format: Raster maps are provided as TIFF images, with an additional
+ "world file" storing the geographic reference (usually with an
+ extension ".tfw").
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </appendix>
+
+ <appendix><title>Working with PostGIS</title>
+ <para>
+ This section focusses on the use of PostGIS in the Thuban framework. For
+ installation and maintenance of spatial databases we refer to the
+ <ulink url="http://postgis.refractions.net">PostGIS Homepage</ulink>.
+ The Thuban PostGIS support requires the
+ <ulink url="http://initd.org/software/psycopg">psycopg module</ulink>.
+ </para>
+
+ <para>
+ Working with PostGIS Databases is seperated into two steps:
+ <itemizedlist>
+ <listitem><para>Opening a Database Connection</para></listitem>
+ <listitem><para>Loading a Data Layer</para></listitem>
+ </itemizedlist>
+ </para>
+ <section><title>Opening a Database Connection</title>
+ <para>
+ Before a data layer can be loaded from a PostGIS database a
+ connection with the database has to be established.
+ <menuchoice>
+ <guimenu>Session</guimenu>
+ <guimenuitem>Database Connections ...</guimenuitem>
+ </menuchoice> opens a dialog for database connection
+ management. In the dialog new connections can be added
+ and existing ones can be removed. Removing a database
+ connection is not possible if the map still displays a
+ layer provided by this database connection.
+ </para>
+ <figure>
+ <title>Database Management Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_db_management.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_db_management.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ To add a new database connection to the session a dialog is
+ opened to specify the relevant connection data. Enter all
+ data relevant for your connection. If the connection fails
+ the dialog remains open and provides some hints on the failure.
+ </para>
+ <figure>
+ <title>Add Database Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_db_add.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_db_add.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ It is important to note that information on database connections are
+ also stored with the session. Passwords are NOT stored. If you load a
+ session with database connections you are asked to enter these
+ passwords again where required.
+ </para>
+
+ </section>
+
+ <section><title>Loading a Data Layer</title>
+ <para>
+ Data layers as part of a map are loaded with the
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Add Database Layer ...</guimenuitem>
+ </menuchoice> menu item. A dialog is raised displaying two choice
+ lists. In the left list all connected databases are shown.
+ Highlighting
+ one of these and issuing a retrieval results in a list of available
+ layer tables from that database. After selection of a
+ layer the dialog is closed.
+ </para>
+ <figure>
+ <title>Add Database Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_add_layer.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_add_layer.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+ </appendix>
+
+ <appendix><title>Supported Projections</title>
+ <para>
+ The following types of projections are directly support by
+ Thuban. The specific values for each are provided by the user
+ to create custom projections. Thuban comes with predefined
+ projections which are available through the Projections dialog.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>Geographic</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para>
+ <literal>Source Data</literal>: either Degrees or Radians
+ </para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Lambert Conic Conformal</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Latitude of 1st standard parallel</literal></para></listitem>
+ <listitem><para><literal>Latitude of 2nd standard parallel</literal></para></listitem>
+ <listitem><para><literal>Central Meridian</literal></para></listitem>
+ <listitem><para><literal>Latitude of Origin</literal></para></listitem>
+ <listitem><para><literal>False Easting</literal> (meters)</para></listitem>
+ <listitem><para><literal>False Northing</literal> (meters)</para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Transverse Mercator</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Latitude</literal>of origin</para></listitem>
+ <listitem><para><literal>Longitude</literal>at central meridian</para></listitem>
+ <listitem><para><literal>Scale Factor</literal>at central meridian</para></listitem>
+ <listitem><para><literal>False Easting</literal> (meters)</para></listitem>
+ <listitem><para><literal>False Northing</literal> (meters)</para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Universal Transverse Mercator</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Zone</literal>
+ (can be guessed appling the Propose button)</para></listitem>
+ <listitem><para><literal>Southern Hemisphere</literal> flag</para></listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Thuban comes with a sample set of map projections for various
+ European countries. Apart from the basic projection they differ
+ especially in their parameterization:
+ </para>
+ <itemizedlist>
+ <listitem><para>Belgium Datum 1972 (Lambert Conic Conformal)</para>
+ </listitem>
+
+ <listitem><para>Gauss-Boaga Zone 1 (Italy, Transverse Mercartor)</para>
+ </listitem>
+
+ <listitem><para>Gauss-Krueger Zone 2 (Germany, Transverse Mercartor)
+ </para>
+ </listitem>
+
+ <listitem><para>Reseau Geodesique Francaise
+ (France, Lambert Conic Conformal)</para>
+ </listitem>
+
+ <listitem><para>UK National Grid (United Kingdom, Transverse Mercartor)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Thuban uses the comprehensive PROJ library for projections. PROJ provides
+ more than the four commonly used projections described above. If needed
+ Thuban can be easily extended to a new projection covered by PROJ.
+ </para>
+ </appendix>
+
+</book>
+
Added: packages/thuban/branches/upstream/current/Doc/manual/thuban-manual.xml
===================================================================
--- packages/thuban/branches/upstream/current/Doc/manual/thuban-manual.xml 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/manual/thuban-manual.xml 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1997 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book
+ PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY imgscale "60">]>
+<!-- $Revision: 2727 $ -->
+<book>
+ <bookinfo>
+ <title>User's Manual for Thuban 1.2 (Draft)</title>
+ <authorgroup>
+ <author>
+ <firstname>Jonathan</firstname><surname>Coles</surname>
+ </author>
+ <author>
+ <firstname>Jan-Oliver</firstname><surname>Wagner</surname>
+ </author>
+ <author>
+ <firstname>Frank</firstname><surname>Koormann</surname>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2003, 2004, 2005, 2006, 2007</year>
+ <holder>Intevation GmbH</holder>
+ </copyright>
+ <revhistory>
+<!-- comment this first revision out when releasing a real version -->
+<!--
+ <revision>
+ <revnumber>SVN version $Id: thuban-manual.xml 2727 2007-02-20 10:44:51Z bernhard $</revnumber>
+ <date></date>
+ <revremark>Under development.</revremark>
+ </revision>
+-->
+ <revision>
+ <revnumber>1.2.0</revnumber>
+ <date>20-Feb-2007</date>
+ <revremark>
+ Removed all installation instructions in favor
+ of a link to the website. It is not wise to
+ double the README contents here.
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>1.0.0</revnumber>
+ <date>22-Jan-2004</date>
+ <revremark>
+ Corresponds to Thuban 1.0.0.
+ New: Installation instructions for Win32.
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>1.0pre3</revnumber>
+ <date>04-Dec-2003</date>
+ <revremark>
+ Corresponds to Thuban 1.0rc1.
+ New: I18n, right button legend menu, EPSG projectons,
+ PostGIS support.
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>1.0pre2</revnumber>
+ <date>29-Aug-2003</date>
+ <revremark>
+ Corresponds to Thuban development release 0.8.1.
+ New: chapter on extensions.
+ </revremark>
+ </revision>
+ <revision>
+ <revnumber>1.0pre1</revnumber>
+ <date>08-Aug-2003</date>
+ <revremark>Corresponds to Thuban development release 0.8.1.</revremark>
+ </revision>
+ </revhistory>
+
+ </bookinfo>
+
+ <chapter><title>Introduction</title>
+ <para>
+ Thuban is an interactive geographic data viewer.
+ Its development had been started because there was no simple interactive
+ viewer for geographic information available as Free Software. Thuban is
+ written mainly in Python and uses the wxWidgets (former wxWindows)
+ library allowing it to
+ run on many different platforms, including GNU/Linux and Windows.
+ </para>
+ <para>
+ Geographic data viewers are a necessary tool as they allow one to
+ get a visual
+ impression of the positional relationship of the information that may not
+ be apparent from simple inspection of the data values themselves.
+ Thuban allows the user to create a session that displays
+ geographic data and then explore that data through navigation and
+ manipulation of how it is drawn. The results can then be saved or printed.
+ </para>
+ <para>
+ Thuban arranges a session in a hierarchy. A session contains a map which
+ consists of layers. Each layer represents a data set. For
+ instance, there may be a layer for roads and another layer for buildings.
+ These layers can either be vector shapes or images.
+ </para>
+
+ <section><title>Installation</title>
+ <para>
+ Thuban is actively supported under Debian 4.0 (Etch)
+ and Windows (XP). Of course it is possible to run Thuban
+ on a variety of other platforms.
+
+ Please check <ulink url="http://thuban.intevation.org/">
+ Thuban's Website
+ </ulink> about how to install Thuban and the lastest information
+ about the supported platforms.
+ </para>
+ </section>
+
+ <section><title>Internationalization</title>
+ <para>
+ Thuban is implemented with internationalization support. So far Thuban
+ is translated by volunteers to the following languages (apart from its
+ main language: English):
+ <itemizedlist>
+ <listitem><para>French</para></listitem>
+ <listitem><para>German</para></listitem>
+ <listitem><para>Italian</para></listitem>
+ <listitem><para>Portuguese (Brazilian)</para></listitem>
+ <listitem><para>Russian</para></listitem>
+ <listitem><para>Spanish</para></listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ To use internationalization under POSIX systems (like GNU/Linux)
+ you have to set the environment variable LC_ALL accordingly (e.g.
+ LC_ALL=fr_FR for the french language support). Please check your
+ systems documentation for details and supported settings.
+ Specifiying LC_ALL on the command line while launching thuban
+ allows appication specific language settings:
+ </para>
+ <programlisting>
+ LC_ALL=fr_FR thuban.py
+ </programlisting>
+
+ <para>
+ MS Windows users have to specify the language to be used via the control
+ bar (which effects all applications).
+ </para>
+ </section>
+
+ <section><title>The Main Window</title>
+ <para>
+ <figure>
+ <title>The Main Window</title>
+ <mediaobject>
+ <imageobject> <imagedata fileref="../images/1_2_mainwindow.png" format="PNG" scale="&imgscale;"/> </imageobject>
+ <imageobject> <imagedata fileref="./images/1_2_mainwindow.ps" format="EPS" scale="&imgscale;"/> </imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ <para>
+ The map window shows the current state of the map and is where
+ the user can interact with the map using the tools.
+ </para>
+
+ <para>
+ The legend on the left displays a list of the current layers and
+ any visible classification groups. In the example, each shape layer
+ has a default classification which specifies how the shapes in each
+ layer are drawn. Layers that are higher in the list appear
+ ``closer'' to the user. The legend can be closed by clicking on the
+ small X in the upper right-hand region of the legend.
+ To open it again, use
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Legend</guimenuitem>
+ </menuchoice>.
+ The legend is also dockable, which means that it can be detached
+ from the main window by clicking on the small button next to the
+ close button. It can be attached by clicking the same button
+ again.
+ </para>
+ <para>
+ The status bar displays different information depending on the
+ current context. If the user is selecting an item from the menu
+ then the status bar will display a short help message indicating
+ what each menu item is for. If the user has a tool selected then
+ the position of the cursor on the map is displayed.
+ </para>
+ <para>
+ The tool bar provides quick access to the commonly needed tools.
+ By hovering over each button the user can see a short messages
+ describing what the tool does. The tools provided are Zoom In, Zoom
+ Out, Pan, Full Extent, Full Layer Extent, Full Shape Extent, Identify,
+ and Label. Each of the tools will be explained in further detail later
+ in the manual.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Session Management</title>
+
+ <section><title>Starting a New Session</title>
+ <para>
+ A new session can be started from
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>New Session</guimenuitem>
+ </menuchoice>.
+ If a session is already loaded and has been modified without
+ being saved a prompt will ask if the current session should
+ be saved. A new session consists of an empty map with no
+ layers, no tables and no projection.
+ </para>
+ </section>
+
+ <section><title>Opening a Session</title>
+ <para>
+ A session can be opened from
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Open Session</guimenuitem>
+ </menuchoice>. A dialog box will open allowing the user to browse
+ for a Thuban Session file. Thuban session files end with
+ <varname>.thuban</varname>. Selecting a file a clicking
+ <guibutton>OK</guibutton> will load the session into Thuban.
+ </para>
+
+ <para>
+ If a session is already loaded and has been modified without
+ being saved a prompt will ask if the current session should
+ be saved.
+ </para>
+
+ <para>
+ Thuban provides a path recovery feature: If a (shape) file referenced
+ in a Thuban session cannot be found at the specified location, the user
+ is prompted a file dialog. Here a new location can be selected for the
+ currents layer data source. Cancelling the dialog removes the layer
+ from the session. If a new location has been selected, Thuban checks
+ this again, if further layers data sources are missing. The user is
+ informed about this and can accept or cancel the suggestion.
+ </para>
+ </section>
+
+ <section><title>Saving a Session</title>
+ <para>
+ A session can be saved from
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Save Session</guimenuitem>
+ </menuchoice>.
+ In the case the session is not a new and unsaved one,
+ the corresponding file is updated with the current session
+ data.
+ In the case the current session is a new one and yet unsaved
+ a dialog box will open allowing the user to browse
+ the file system and select a place to save the session. Thuban
+ sessions should be saved under a name ending in
+ <varname>.thuban</varname>. If the file already exists the user
+ will be prompted to save under a different name or overwrite the
+ existing file.
+ </para>
+ </section>
+
+ <section><title>The Session Info-Tree</title>
+ <para>
+ <figure>
+ <title>Session Info Tree</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/2_4_session_tree.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/2_4_session_tree.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The session info-tree is primarily intended for developers working
+ with Thuban. It displays many of the internal values for the session,
+ map, and layers. It can be opened from
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Session Tree</guimenuitem>
+ </menuchoice>.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Map Management</title>
+ <para>
+ The map consists of a number of layers where each layer represents a
+ different type of data set. By interacting with the map the user can
+ visually explore the data.
+ </para>
+ <para>
+ The map can have a name that will appear in the Thuban title bar.
+ The map name can be changed using
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Rename</guimenuitem>
+ </menuchoice>.
+ </para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_rename_map.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_rename_map.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Rename Map</phrase> </textobject>
+ </inlinemediaobject>
+ </para>
+
+ <section><title>Adding and Removing Layers</title>
+ <para>
+ There are three types of layers that can be added to a map:
+ Shape layers, database layers
+ and image layers. Shape layers are stored in Shapefile format, a
+ widely used file format for storing geographic objects. These
+ files have the extension ``.shp''. Associated with
+ the shape file is a database file which stores attributes for
+ each shape in the Shape file. This file, in dBase format,
+ has the extension ``.dbf''. Both files must have the same base name.
+ For example, if there is a shape file named roads.shp there must
+ also be a file roads.dbf.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Shape layers can be added to the map with
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Add Layer</guimenuitem>
+ </menuchoice>.
+ Initially, only the ``.shp'' files are shown which is enough for the
+ selection. However, if you switch to display all files and select one
+ of the associated files (e.g. ``.dbf''), Thuban will recognize the base
+ name and load the corresponding Shape file.
+ </para>
+ <para>
+ The file dialog for Shape files allows to select multiple files.
+ Use the shift-button together with the left mouse button to extend
+ the selection.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Database layers can be added to the map with
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Add Database Layer</guimenuitem>
+ </menuchoice>.
+ A dialog with two lists is opened. The left list displays all
+ database connections currently open for the session. You can retrieve
+ a list of available layers from the selected database which is
+ displayed on the right hand. From this list one layer can be selected,
+ the dialog is closed afterwards.
+ </para>
+ <para>
+ See appendix ``Working with PostGIS'' for details.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Image layers can be added to the map with
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Add Image Layer</guimenuitem>
+ </menuchoice>.
+ It is important to select a valid image file that has geographic
+ data associated with it. The data can be embedded in the file itself,
+ or in another file. If geographic information cannot be found, Thuban
+ will report an error.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section><title>Navigation</title>
+ <para>
+ The map can be explored by using the navigation tools available on
+ the tool bar or from the
+ <menuchoice><guimenu>Map</guimenu></menuchoice> menu.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ The ZoomIn tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_zoomin.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_zoomin.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>ZoomIn Tool</phrase> </textobject>
+ </inlinemediaobject>
+ enlarges a region of the map. Clicking once on the map
+ will double the magnification and center the map on the point that
+ was clicked. Clicking and dragging selects a region that will be
+ enlarged to fit the window.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The ZoomOut tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_zoomout.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_zoomout.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>ZoomOut Tool</phrase> </textobject>
+ </inlinemediaobject>
+ shrinks the map so that a larger region is visible. A single click
+ reduces the magnification by a factor of two. Clicking and dragging
+ selects a box such that the current contents of the window will be
+ scaled to fit into that box.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Pan tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_pan.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_pan.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Pan Tool</phrase> </textobject>
+ </inlinemediaobject>
+ allows the user to move the map around by clicking and dragging.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Full Extent tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fullextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fullextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Full Extent Tool</phrase> </textobject>
+ </inlinemediaobject>
+ rescales the viewable region so that the entire map is visible.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Full Layer Extent tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fulllayerextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fulllayerextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Full Layer Extent Tool</phrase> </textobject>
+ </inlinemediaobject>
+ rescales the viewable region so that the currently selected
+ layer fits within the window. If no layer is selected this button
+ will be disabled.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Full Shape Extent tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_2_fullshapeextent.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_2_fullshapeextent.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Full Shape Extent Tool</phrase> </textobject>
+ </inlinemediaobject>
+ rescales the viewable region so that the currently selected
+ shape fits within the window. If the shape is a point, it is
+ centered and the map is zoomed all the way in. If no shape is
+ selected this button will be disabled. This feature is especially
+ helpful when identifying an object related to a selected record
+ in a tableview (see below).
+
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section><title>Object Identification</title>
+ <para>
+ Objects on the map can be identified using the Identify tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_3_identify.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_3_identify.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Identify Tool</phrase> </textobject>
+ </inlinemediaobject>.
+ Clicking on an object selects that object and opens a dialog which
+ shows all the table attributes for that object. Any current selection
+ is lost. Objects on the map are typically shapes and this document
+ will often refer to objects as shapes.
+ </para>
+ </section>
+
+ <section><title>Object Labeling</title>
+ <para>
+ Objects can be labeled using the Label tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_3_label.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_3_label.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Label Tool</phrase> </textobject>
+ </inlinemediaobject>.
+ Clicking on an object selects that object and opens a dialog which
+ displays the table attributes for that object. An attribute can
+ be selected to be the label on the map. The label will be placed
+ at the center of the shape. Clicking on an object that already has
+ a label will remove the label.
+ </para>
+ </section>
+
+ <section><title>The Legend</title>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_legend.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_legend.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Legend</phrase> </textobject>
+ </inlinemediaobject>
+ </para>
+ <para>
+ The Legend provides an overview of the layers in the map. Layers
+ that appear higher in the legend will appear ``closer'' to the user.
+ If a layer supports classification (currently, only shape layers
+ have this feature) then the classification groups will be shown
+ below each layer. The properties for each group are also displayed
+ with a small graphic. Polygon layers appear as rectangles, lines
+ appear as curved lines, and points appear as circles.
+ </para>
+ <para>
+ Along the top of the legend is a toolbar which allows quick access
+ to some of the layer manipulation options under
+ <menuchoice><guimenu>Map</guimenu></menuchoice>.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The Move Layer to Top tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_totop.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_totop.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Move Layer to Top</phrase> </textobject>
+ </inlinemediaobject> raises the selected layer to the top of the map.
+ </para>
+ </listitem>
+ <listitem>
+
+ <para>
+ The Move Layer Up tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_moveup.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_moveup.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Move Layer Up</phrase> </textobject>
+ </inlinemediaobject> raises the selected layer one level.
+ </para>
+ </listitem>
+ <listitem>
+
+ <para>
+ The Move Layer Down tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_movedown.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_movedown.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Move Layer Down</phrase> </textobject>
+ </inlinemediaobject> lowers the selected layer one level.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The Move Layer to Bottom tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_tobottom.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_tobottom.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Move Layer to Bottom</phrase> </textobject>
+ </inlinemediaobject> lowers the selected layer to the bottom of the map.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The Visible tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_visible.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_visible.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Visible</phrase> </textobject>
+ </inlinemediaobject> shows the selected layer in the map if it was
+ hidden.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The Invisible tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_invisible.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_invisible.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Invisible</phrase> </textobject>
+ </inlinemediaobject> hides the selected layer in the map.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ The Properties tool
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="../images/3_5_props.png" format="PNG" scale="&imgscale;"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="./images/3_5_props.eps" format="EPS" scale="&imgscale;"/>
+ </imageobject>
+ <textobject> <phrase>Properties</phrase> </textobject>
+ </inlinemediaobject> opens the layer's properties dialog box.
+ Double-clicking on a layer or a group of a layer will open the
+ properties dialog for that layer.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The most used layer related actions are also available from a
+ popup menu. It is raised when a layer is clicked with the right mouse
+ button.
+ </para>
+
+ <para>
+ <figure>
+ <title>Layer Popup Menu</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/3_5_popup_menu.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/3_5_popup_menu.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ <para>
+ Along the bottom of the legend is the scalebar. The scalebar
+ will be available if there are any layers and the map has a
+ projection set.
+ </para>
+ </section>
+
+ <section><title>Exporting</title>
+ <para>
+ Under Windows, maps can be exported in Enhanced Metafile format
+ (<varname>.wmf</varname>)
+ from
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Export</guimenuitem>
+ </menuchoice> for use in reports, presentations, or further
+ modification. The current map view, legend, and, if available,
+ scalebar are exported. Under other platforms this option is not
+ available. Clicking this menu item open a file selection dialog
+ that lets the user select a location to export the map.
+ </para>
+ </section>
+
+ <section><title>Printing</title>
+ <para>
+ The map can be printed using
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Print</guimenuitem>
+ </menuchoice>. The current map view, legend, and, if available,
+ scalebar are printed. A standard printing dialog will open allowing
+ the user to configure the printer. This dialog will differ depending
+ on which platform Thuban is running.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Layer Management</title>
+ <para>
+ </para>
+
+ <section><title>Types of Layers</title>
+ <para>
+ There are three types of layers supported by Thuban: shape layers,
+ database layers and
+ image layers. Shape layers consist of vector based shapes with
+ geo-referenced coordinates. There are three types of supported
+ shapes: polygons, lines (arc), and points. Database layers are similar
+ to shape layers but loaded from a database instead of the file system.
+ Image layers can be any image
+ file format supported by the Geo-spatial Data Abstraction Library
+ (GDAL). The images must have geographic
+ coordinate data either embedded within the file or in a separate
+ file that is in the same directory as the image file. GeoTIFF files
+ work very well with Thuban and were designed specifically to be image
+ layers in GIS programs.
+ </para>
+ <para>
+ All actions in the
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ </menuchoice> menu act on the currently selected layer in the legend.
+ </para>
+ </section>
+
+ <section><title>Properties</title>
+ <para>
+ To view the properties for a layer it must first be selected in the
+ legend. The menu option
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Properties</guimenuitem>
+ </menuchoice> opens a dialog that displays a layer's properties.
+ All layers have a title which can be modified in the text field
+ provided. The type of layer is also shows. If the type is a type
+ of shape (polygon, arc, point) the classification table will be
+ shown. Image layers have no other properties other than title
+ and type.
+ </para>
+ <para>
+ <figure>
+ <title>Properties Window</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/4_2_layer_properties.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/4_2_layer_properties.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ <figure>
+ <title>Properties Window</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/4_2_raster_layer_properties.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/4_2_raster_layer_properties.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ </section>
+
+ <section><title>Visibility</title>
+ <para>
+ Sometimes it is not desirable to view all layers at the same time.
+ Some layers may take a long time to draw and so while navigating
+ around the map the user may not want to wait for the map to redraw
+ all the layers each time the map is changed. Each layer can be
+ independently turned on or off using the
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Show</guimenuitem>
+ </menuchoice>
+ or
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Hide</guimenuitem>
+ </menuchoice> options respectively.
+ </para>
+ </section>
+
+ <section><title>Duplication</title>
+ <para>
+ Layers and all their properties, including classifications, can
+ be duplicated using
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Duplicate</guimenuitem>
+ </menuchoice>. Duplicating a layer is useful if the user wishes
+ to model a layer in several different ways. Even though the layers
+ overlap, by carefully selecting the shape properties it is possible
+ to display several pieces of information at once. For example, one
+ copy of a roads layer may be classified on a length property and
+ another copy may be classified on a type property. If the length
+ property was expressed with color and the type property expressed
+ with line thickness then it would be possible to view both
+ classifications by placing the type property copy over the
+ length property copy.
+ </para>
+ </section>
+
+ </chapter>
+
+ <chapter><title>Layer Classifications</title>
+ <para>
+ A layer classification is a way of assigning drawing properties to
+ groups of shapes based on attributes stored in the layer's table.
+ Only layer's with shapes can have a classification; image layers
+ cannot be classified.
+ </para>
+ <para>
+ A classification consists of a number of groups, each group
+ having a value or range of values to match against, and symbol
+ properties which control how a shape is drawn on the map. The user
+ selects which field in the table is used by the classification and
+ when the map is drawn the value for that field for each shape is
+ compared with each group's value. The properties of the first group
+ to match are used to draw the shape. This allows the user to get a
+ visual impression of not only how the data is laid out but also what
+ kind of data lies where.
+ </para>
+ <para>
+ A layer always has a classification. When a new layer is added to the
+ map, a default classification is created with the DEFAULT group. This
+ group cannot be removed but can be hidden (see below). Every shape in the
+ layer, regardless of its attributes, will match this group if no other
+ group matches.
+ </para>
+
+ <section><title>Editing Classifications</title>
+ <para>
+ A layer's classification can be modified under the properties dialog
+ (<menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Properties</guimenuitem>
+ </menuchoice>). The layer's classification field can be set to None,
+ which simply assigns a DEFAULT group to the classification. No new
+ groups can be added to the classification if the field is None.
+ The user must first select a field to classify on. New groups can
+ be added to the classification with the <guibutton>Add</guibutton>
+ button.
+ </para>
+ <para>
+ To apply the changes to the map the user can click
+ either <guibutton>Try</guibutton> or <guibutton>OK</guibutton>.
+ <guibutton>Try</guibutton> will not close the dialog box, allowing
+ the user to see how the classification changes the map.
+ <guibutton>Revert</guibutton> will undo the last classification applied
+ to the map. <guibutton>OK</guibutton> will commit the changes and
+ close the dialog. The user will be unable to undo the changes.
+ <guibutton>Close</guibutton> simply closes the dialog box. If any
+ changes have not been applied with <guibutton>Try</guibutton> the
+ changes will not be applied to the map.
+ </para>
+ <para>
+ <figure>
+ <title>Properties Window</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_classification.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_classification.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The order of the groups in the classification is significant
+ except for the DEFAULT group, which remains at the top. When shapes
+ are matched against groups the matching begins at the first group
+ after the DEFAULT group so that groups higher in the list will
+ be checked first. Matching for a
+ given shape will stop at the first group that matches. The user can
+ use <guibutton>Move Up</guibutton> and <guibutton>Move Down</guibutton>
+ to change the order of the groups. The DEFAULT group will always
+ match a shape that hasn't matched another group.
+ </para>
+ <section><title>Visible</title>
+ <para>
+ The Visible column has check-boxes that determine whether a
+ classification group will be displayed in the legend. This is
+ useful if the user knows that the groups completely cover
+ the data set and don't want the DEFAULT group to be displayed
+ in the legend and on a printout.
+ </para>
+ </section>
+ <section><title>Symbols</title>
+ <para>
+ Each type of shape has its own type of symbol. Thuban supports three
+ types of shapes: polygons, lines, and points. Polygons and points
+ have outline and fill color, while lines have only line color. Each
+ group has associated symbol properties. To edit the symbol
+ properties for a group the user can double click on the Symbol
+ column or select a group and click the
+ <guibutton>Edit Symbol</guibutton> button.
+ </para>
+ </section>
+ <section><title>Value</title>
+ <para>
+ The Value column of the classification table is the value that will
+ be matched when the map is being drawn. The type of filter that can
+ entered into this field depends on the type of data of the
+ classification field:
+ </para>
+ <para>
+ If the field is of type Text, anything entered
+ into the field is valid. By default the text will be compared
+ literally to the
+ value of the shape attribute, including case sensitivity.
+ Alternatively the comparison can be based on regular experessions.
+ Right-click on the row label to open a popup menu with the options
+ <guibutton>Singleton</guibutton> (literal comparison) and
+ <guibutton>Pattern</guibutton> (regular expressions).
+ </para>
+ <para>
+ If the type is Integer, then any valid integer may be entered. In
+ addition, with special syntax, a range of values can be entered.
+ A range from <varname>start</varname> to <varname>end</varname>
+ inclusive is specified like this: <literal>[start;end]</literal>.
+ The exclusive range is specified like this:
+ <literal>]start;end[</literal>. Ranges can include infinity like
+ this: <literal>[-oo;oo]</literal>. Field types can also be of type
+ Decimal. They represent any rational number and can be used in
+ ranges as well.
+ </para>
+ </section>
+ <section><title>Label</title>
+ <para>
+ By default, the text that is displayed for a group in the legend
+ is the value for that group. The label can substitute a more
+ descriptive term in the legend.
+ </para>
+ </section>
+ </section>
+
+ <section><title>Generating Classes</title>
+ <para>
+ <figure>
+ <title>Generate Class</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_3_genclass.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_3_genclass.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Creating a classification by hand can be tedious.
+ Thuban, therefore, provides a means of generating an entire
+ classification at once while still giving the user control over
+ how it appears. Clicking <guibutton>Generate Class</guibutton>
+ opens the <varname>Generate Classification</varname> dialog.
+ Under the <varname>Generate</varname> pull down there are at most
+ three different ways to generate classifications:
+ Unique Values, Uniform Distribution, and Quantiles. Some options
+ may not be available if the data type for the field does not
+ support them. For instance, <varname>Uniform Distribution</varname>
+ doesn't make sense for a Text field.
+ </para>
+ <para>
+ For every way of generating a classification, a color scheme must
+ be selected. Thuban provides several different color schemes that
+ affect how the group properties change over the classification.
+ It may be desirable that only certain properties change over the
+ classification. If the shape type is a polygon or a point then
+ the <guibutton>Fix Border Color</guibutton> option will be available.
+ This allows the user to select a border color for all classification
+ groups.
+ It is also possible to create a custom color scheme. Selecting
+ this option will display two symbols: the one of the left has the
+ properties of the first group and the one on the right has the
+ properties of the last group. Thuban will interpolate between these
+ two properties to generate the other groups.
+ <figure>
+ <title>Custom Color Scheme</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_custom_ramp.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_custom_ramp.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The Unique Values option lets the user select specific values that
+ appear in the table. Clicking <guibutton>Retrieve From Table</guibutton>
+ searches the table for all unique values and displays them in the
+ list on the left. Items can be selected and moved to the list on the
+ right. Each list can be sorted or reversed for easier searching.
+ The classification that is generated will be in the same order as
+ the list on the right.
+ <figure>
+ <title>Unique Values</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_unique_values.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_unique_values.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The Uniform Distribution option creates a user specified number of
+ groups of ranges such that each range covers equal intervals. The
+ minimum and maximum values can automatically be retrieved from the
+ table by clicking <guibutton>Retrieve From Table</guibutton>. The
+ stepping is how large each interval is. Adjusting this value will
+ automatically recalculate how many groups is appropriate.
+ <figure>
+ <title>Uniform Distribution</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_uniform_dist.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_uniform_dist.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The Quantiles option generates ranges based on the number of items
+ in the table. For example, by specifying five groups Thuban will
+ generate five groups with appropriate ranges such that 20% of the table
+ data is in each group. If it is impossible to generate exact
+ groupings, Thuban will issue a warning but allow the user to continue.
+ <figure>
+ <title>Quantiles</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/5_2_quantiles.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/5_2_quantiles.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Projection Management</title>
+ <para>
+ Projections control how the geographic data is displayed on the screen.
+ If multiple layers are loaded into Thuban where the geographic data
+ is in a different projection system, then the user must specify a
+ projection for each layer. The user must also tell Thuban which
+ projection the map is in. This can be the same as the layers or a different
+ projection in which case the layers are reprojected into that space.
+ The map projection can be set using
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Projection</guimenuitem>
+ </menuchoice> and the layer projection can be set using
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Projection</guimenuitem>
+ </menuchoice>.
+ <figure>
+ <title>Projection Window</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/6_projection.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/6_projection.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Thuban is distributed with a sample collection of projections and the
+ set of coordinate systems as used by the EPSG
+ (European Petroleum Survey Group). This quite large set is only displayed
+ if activated by the according checkbox. The set falls into two parts:
+ deprecated lists all projections which are no longer part of the
+ EPSG data base.
+ </para>
+ <para>
+ The
+ user can create new projections and make them available to all
+ future Thuban sessions. They may also be exported and imported so
+ that custom projections can be distributed.
+ </para>
+ <section><title>Selecting a Projection</title>
+ <para>
+ The available projections are listed on the left. If the layer
+ or map already has a projection it will initially be highlighted
+ and will end with <varname>(current)</varname>. Selecting
+ <varname><None></varname> will cause Thuban to use the data as
+ it appears in the source file and will not use a projection.
+ </para>
+ </section>
+ <section><title>Editing a Projection</title>
+ <para>
+ Whenever a projection is selected from the list its properties
+ are displayed on the right. These properties can be changed
+ and the changes saved to the selected projection using
+ <guibutton>Update</guibutton>. Only a projection that comes
+ from a file can be updated, so if the current layer's projection
+ is selected, <guibutton>Update</guibutton> will be disabled.
+ <guibutton>Add to List</guibutton> adds the projection to the
+ list of available projections as a new entry, and thus makes it
+ available to future Thuban sessions. Clicking <guibutton>New</guibutton>
+ will create an entirely new, empty projection. The
+ <guibutton>Remove</guibutton> button will permanently remove a
+ projection from the list of available projections.
+ </para>
+ <para>
+ To apply the selected projection to the map the user can click
+ either <guibutton>Try</guibutton> or <guibutton>OK</guibutton>.
+ <guibutton>Try</guibutton> will not close the dialog box, allowing
+ the user to see how the projeciton changes the map.
+ <guibutton>Revert</guibutton> will undo the last projection applied
+ to the map. <guibutton>OK</guibutton> will commit the changes and
+ close the dialog. The user will be unable to undo the changes.
+ <guibutton>Close</guibutton> simply closes the dialog box. If no
+ selection has been applied with <guibutton>Try</guibutton> the
+ selection will not be applied to the map.
+ </para>
+ </section>
+ <section><title>Importing/Exporting Projections</title>
+ <para>
+ The projections that appear in the list of available projections
+ can be exported to another file that the user chooses. By selecting
+ one or more projections and clicking <guibutton>Export</guibutton>
+ the user will be able to select a file in which to store those
+ projections.
+ The file can then be distributed to other Thuban users. To import
+ a projection file the user can click <guibutton>Import</guibutton>.
+ The imported projections are added to the list and are then available
+ to the current session and any future Thuban sessions.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter><title>Table Management</title>
+ <para>
+ Thuban distinguishes two different types of tables: Attribute tables
+ (which belong to a layer) and normal data tables. Both provide
+ the same general functionality with the difference that actions on an
+ attribute table might also effect the map display.
+ </para>
+
+ <section><title>Table View</title>
+ <para>
+ <figure>
+ <title>Table View</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/7_1_table_view.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/7_1_table_view.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ Thuban provides a standard dialog to display table contents, the
+ Table View. The view has five sections: The title, selections,
+ the table grid, export functions, and the status bar.
+ </para>
+ <para>
+ The title bar identifies the table with its name.
+ </para>
+ <para>
+ The selections box let the user perform simple analysis on the data
+ based on comparisons: The first choice must be a field identifier of
+ the table, the second choice determines the type of comparison. The
+ third choice can be either a specific value (interpreted as numerical
+ or string depending on the type of the first field) or a second field
+ identifier. Thus you can perform analysis like selecting all
+ records where <literal>population > 10000</literal> or
+ <literal>cars_per_inhabitant < bikes_per_inhabitant</literal>
+ (note that the field names are only explanatory, the dBase files
+ allow only 11 character field names).
+
+ Selections can be combined either by applying a selection only on
+ a previously selected set of records or by adding the results of a
+ selection to a previous set. The default is that a selection replaces
+ earlier results.
+ </para>
+ <para>
+ The table grid shows the contents of the table (one record per row),
+ with highlighted selection results. Columns and rows can be resized.
+ </para>
+ <para>
+ The contents of a table can be exported into a file, either dBase
+ format (DBF) or comma separated values (CSV). The
+ <guibutton>Export</guibutton> button
+ raises a file dialog to specify a path and file name, the export type
+ is determined by the file extension (either .dbf or .csv).
+
+ The <guibutton>Export Selection</guibutton> button works similarly
+ but exports only the selected records.
+
+ The <guibutton>Close</guibutton> button closes the table view window.
+ This is different from the menu item
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Close</guimenuitem>
+ </menuchoice> which unloads the table from Thuban.
+ </para>
+ <para>
+ The status bar displays some statistics about the table and optional
+ selection results.
+ </para>
+ </section>
+
+ <section><title>General Functionality (Menu Table)</title>
+ <para>
+ The general functions affect all tables open in Thuban. Attribute
+ tables are considered here as normal data tables (with the exception
+ that they cannot be closed).
+ </para>
+ <section><title>Open</title>
+ <para>
+ The
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Open</guimenuitem>
+ </menuchoice>
+ item raises a file dialog to let you select a
+ dBase file from the file system to be loaded into Thuban read-only.
+ On <guibutton>OK</guibutton> the selected file is loaded and a
+ table view is opened.
+ </para>
+ </section>
+
+ <section><title>Close</title>
+ <para>
+ The
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Close</guimenuitem>
+ </menuchoice>
+ item raises a dialog listing the currently open
+ data tables
+ (loaded via
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Open</guimenuitem>
+ </menuchoice>). Selected tables are dereferenced on confirmation.
+ Since tables are opened read-only the contents of the tables are
+ not affected.
+
+ Any open views of the tables are closed as well.
+
+ Tables used in a join cannot be closed.
+ </para>
+ </section>
+
+ <section><title>Rename</title>
+ <para>
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Rename</guimenuitem>
+ </menuchoice> changes the table title.
+ </para>
+ </section>
+
+ <section><title>Show</title>
+ <para>
+ The
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Show</guimenuitem>
+ </menuchoice>
+ item raises a list of available tables (explicitly
+ loaded, attribute tables, results of a join). Selected tables are
+ show in tables views on <guibutton>OK</guibutton>.
+ </para>
+ </section>
+
+ <section><title>Join</title>
+ <para>
+ <figure>
+ <title>Join Tables</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/7_2_5_join.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/7_2_5_join.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+ <para>
+ The
+ <menuchoice>
+ <guimenu>Table</guimenu>
+ <guimenuitem>Join</guimenuitem>
+ </menuchoice>
+ item raises a dialog to specify the two tables to be
+ joined. The join results in a new table named 'Join of "left table"
+ and "right table"'.
+
+ The dialog lets you select the two tables to be joined and the two
+ fields the join has to be performed on. By default, the new
+ table contains only those records which are matched by the join.
+
+ If you want to preserve the records of the left table you can
+ perform an outer join. The fields from the right table for records
+ not matched by the join are filled with <varname>None</varname> in
+ this case.
+ </para>
+ </section>
+
+ </section>
+ <section><title>Attribute Tables</title>
+ <para>
+ To clearly separate between both types of tables (data and
+ attribute), Thuban provides functionality regarding the attribute
+ tables under the <menuchoice><guimenu>Layer</guimenu></menuchoice> menu.
+ </para>
+
+ <section><title>Show Table</title>
+ <para>
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Show Table</guimenuitem>
+ </menuchoice>
+ opens the attribute table of the currently active layer in a table
+ view.
+
+ In addition to the functionality described above selections
+ affect also the map display: objects related to selected records
+ are highlighted.
+ </para>
+ </section>
+
+ <section><title>Join Table</title>
+ <para>
+ Unlike the join described above, the join does not result in a
+ new table. The attribute table of the currently active layer is the
+ left table and other tables are joined to this table. The results of
+ the join are available for classification.
+
+ As a consequence, the join cannot result in fewer
+ records than the source attribute table. The user is warned if the
+ right table does not fulfill this constraint. An outer join must be
+ used in such cases.
+ </para>
+ </section>
+
+ <section><title>Unjoin Table</title>
+ <para>
+ As said above, a normal table cannot be closed while it is still
+ used in a join. While the joined table resulting from a join of
+ normal tables can be simply closed (and thereby dereferencing
+ the source tables), this is not possible for attribute tables.
+
+ Hence joins on attribute tables must be solved explicitly. This is
+ what the
+ <menuchoice>
+ <guimenu>Layer</guimenu>
+ <guimenuitem>Unjoin Table</guimenuitem>
+ </menuchoice>
+ item is used for: The last join for the currently
+ active layer is solved.
+ </para>
+ </section>
+ </section>
+ </chapter>
+
+ <chapter><title>Extensions</title>
+ <para>
+ Thuban is designed to be extensible. The term Extension is used as a
+ general term for anything that extends Thuban.
+ This chapter introduces into some oppportunities how to add and
+ handle extra functionality developed by your own or third parties.
+ </para>
+
+ <section><title>Add personal extensions via thubanstart.py</title>
+ <para>
+ After Thuban has been started for the first time, a directory
+ .thuban is created within your home directory.
+ There you can add a file thubanstart.py which will be imported
+ by Thuban at start-up. It is recommended to add only import-statements
+ to this file to keep the actual code of extensions separate.
+ </para>
+ <para>
+ The modules to import must either be found through the environment
+ variable PYTHONPATH or directly be placed into the .thuban-directory.
+ </para>
+ <para>
+ As an example, copy the file examples/simple_extensions/hello_world.py
+ of the Thuban source code into the .thuban-directory of your home
+ directory. Now add add the statement import hello_world to the
+ file thubanstart.py and run Thuban. You will notice an additional
+ menu <menuchoice><guimenu>Extensions</guimenu></menuchoice> where
+ the new item for the Hello-World extension is placed - select it
+ to see the Hello-World message.
+ </para>
+ </section>
+
+ <section><title>Extensions included in Thuban package</title>
+ <para>
+ The extensions described in this section are part of the
+ Thuban package, but not activated by default.
+ You will find them in the Thuban installation directory
+ under <literal>Extensions/</literal>. Activate them as personal
+ extensions via PYTHONPATH as described in the previous section.
+ Stable extensions will appear under the menu
+ <menuchoice><guimenu>Extensions</guimenu></menuchoice> and
+ extensions which are in experimental state and therefore
+ not fully functional under
+ <menuchoice><guimenu>Experimental</guimenu></menuchoice>.
+ </para>
+
+ <section><title>Stable extensions</title>
+ <para>
+ These extensions provide extra-functionality to Thuban
+ that has not (yet) been integrated in the main application.
+ They are considered to be free of bugs, but may be
+ further polished with helpful user interactions.
+ </para>
+ <section><title>gns2shp</title>
+ <para>
+ This tool converts data of the Geospatial Names Server
+ (GNS, see <ulink url="http://www.nima.mil/gns"/>)
+ into Shapefile format.
+ The above web-site offer to download named places
+ information grouped by countries for all of the world
+ except USA for which other data are provided.
+ </para>
+ <para>
+ If you download and unpack a package, you will have
+ a text-file with suffix .txt.
+ Selecting such a file via gns2shp will create the
+ corresponding Shapefile with the same basename and
+ place it in the same direcory. Afterwards it
+ is automatically loaded into Thuban.
+ The Shapefile will not automatically be delete afterwards.
+ </para>
+ <para>
+ The gns2shp.py module can also be executed on the
+ command line for batch processing purposes.
+ </para>
+ <para>
+ A sample (<literal>ls.txt</literal> for Liechtenstein)
+ is included in the directory
+ <literal>Extensions/gns2shp/test</literal>.
+ </para>
+ </section>
+ <section><title>SVG Export</title>
+ <para>
+ Map and legend can be exported separately in the
+ Thuban-Map-SVG format.
+ You get files that comply with
+ the Scalable Vector Graphics (SVG) 1.1 Specification
+ and can be read by many vector drawing applications.
+ </para>
+ <para>
+ Goal of svgexport is to provide
+ the start of a printing pipeline for Thuban.
+ For this purpose the written Thuban-Map-SVG files
+ contain information that can be used in postprocessing.
+ Typically a general vector drawing application is
+ more powerful then a geographic information viewer;
+ e.g. having much fancier symbols and fonts.
+ Also users benefit much more when learning to use a
+ more general application they can also use for other
+ tasks. So the charming idea is to enable
+ the drawing application to postprocess a Thuban maps.
+ So thee xtra information in the format will make it
+ possible to export from Thuban and if a few geoobjects
+ change, and keep the general layout and style
+ of the full map in the vector drawing appplication.
+ </para>
+ <para>
+ Markus Rechtien has developed a prototype of this
+ printing pipline as his Diplom thetis, showing
+ the feasability of Bernhard Reiter's concept.
+ Scripts exist for the drawing application Skencil
+ (<ulink url="http://www.skencil.org"/>).
+ </para>
+ <para>
+ Technical notes: the names of the layers are used
+ as base for ids within the SVG format.
+ If you try to export with two layers having
+ the same name, you will get a name clash error.
+ Just change one of the layer names and try again.
+ </para>
+ </section>
+ </section>
+ <section><title>Experimental extensions</title>
+ <para>
+ All all of these functions have to be handled with care,
+ since they are neither complete nor well tested.
+ They are to be seen as a proof-of-concept and may
+ additionally in some cases of practical help.
+ </para>
+ <para>
+ Any interest on further improvement of these extensions
+ should be communicated towards the developer and user
+ community.
+ </para>
+
+ <section><title>importAPR</title>
+ <para>
+ This command offer to load an ESRI® ArcView® project
+ file (suffix .apr) and convert it for use within Thuban.
+ After selecting a apr-file to load, a list
+ will be presented that offers to select one of the views
+ of the apr-file, provided there is more than one.
+ Furthermore, the Session Info-Tree is extended with
+ a complete representation of the parsed apr-file.
+ </para>
+ <para>
+ The legend of Thuban does not yet cover all of the elements as
+ supported by the legend of ArcView®. Therefore, the Thuban
+ map will look different. Furthermore, the apr-format is
+ a proprietary format, not openly documented.
+ Therefore, the interpretation is
+ partly based on reverse engeneering and good guessing.
+ </para>
+ <para>
+ The file-paths within the apr-file may not fit and potentially
+ are subject to fix in the apr-file. You can do this
+ applying any text editor. The paths are either absolute
+ or relative from where Thuban has been started.
+ </para>
+ <para>
+ A sample for the Iceland data is included as
+ <literal>Extensions/importAPR/samples/iceland.apr</literal>.
+ The file-paths are relative from the Thuban main directory.
+ </para>
+ </section>
+ </section>
+ </section>
+
+ <section><title>Writing simple extensions</title>
+ <para>
+ Writing an extension for Thuban basically means to
+ implement the extra functionality in Python with all of the
+ Thuban classes, methods and variables available.
+ </para>
+ <para>
+ All classes and their methods are documented in the source code
+ (see their doc-strings). Here is an example from
+ Thuban/Model/layer.py that describes some of the methods
+ of a Layer object:
+ </para>
+ <programlisting>
+ <![CDATA[
+class BaseLayer(TitledObject, Modifiable):
+
+ """Base class for the layers."""
+
+ def __init__(self, title, visible = True, projection = None):
+ """Initialize the layer.
+
+ title -- the title
+ visible -- boolean. If true the layer is visible.
+ """
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.visible = visible
+ self.projection = projection
+
+ def Visible(self):
+ """Return true if layer is visible"""
+ return self.visible
+
+ def SetVisible(self, visible):
+ """Set the layer's visibility."""
+ self.visible = visible
+ self.issue(LAYER_VISIBILITY_CHANGED, self)
+
+ def HasClassification(self):
+ """Determine if this layer support classifications."""
+...
+ ]]>
+ </programlisting>
+ <para>
+ This example intends to give you an impression of the
+ source-code-level documentation.
+ You have to make yourself familiar with
+ the Python programming language to understand some special
+ code elements.
+ </para>
+ <section><title>hello_world.py</title>
+ <para>
+ Traditionally, the first example should welcome the world.
+ Most of the code handles the frame for integrating a menu
+ item into Thuban while the actual raising of a message
+ is done in a single line.
+ </para>
+ <programlisting>
+ <![CDATA[
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend Thuban with a sample Hello World to demonstrate simple
+extensions.
+"""
+
+__version__ = '$Revision: 2727 $'
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+def hello_world_dialog(context):
+ """Just raise a simple dialog to greet the world.
+
+ context -- The Thuban context.
+ """
+ context.mainwindow.RunMessageBox(_('Hello World'), _('Hello World!'))
+
+
+# create a new command and register it
+registry.Add(Command('hello_world', _('Hello World'), hello_world_dialog,
+ helptext = _('Welcome everyone on this planet')))
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally bind the new command with an entry in the extensions menu
+extensions_menu.InsertItem('hello_world')
+ ]]>
+ </programlisting>
+ </section>
+ <section><title>Registering a Command</title>
+ <para>
+ Mainly, our new function has to be registered to the Thuban
+ framework in order to connect it to the menu. A registered
+ command can also be connected to e.g. a toolbar button.
+ </para>
+ <para>
+ The instances and classes for this are imported at the beginning.
+ Any code not inside a method or class is directly executed when
+ the source-code module is imported. Therefore, the second
+ part of this example consist of the plain statements to create a new
+ Command and to add it to the menu.
+ </para>
+ <para>
+ By convention, it looks for a menu registered as ``extensions'' to
+ insert the new command. If it does not exist yet, it gets created.
+ It is advisable to copy this code for any of your extensions.
+ </para>
+ </section>
+ <section><title>The Thuban context</title>
+ <para>
+ A registered command that is called, always receives the
+ Thuban context. This instance provides our method with
+ hook references to all important components of the Thuban
+ application.
+ </para>
+ <para>
+ In the example hello_world.py, our function uses the
+ mainwindow component which offers a method to raise a
+ message dialog. In total there are three hooks:
+ <itemizedlist>
+ <listitem>
+ <para>application:
+ This object is the instance of the Thuban Application class.
+ Except maybe for loading or savinf sessions, you will not
+ need this object for a simple extension.
+ See Thuban/UI/application.py for the API.
+ </para>
+ </listitem>
+ <listitem>
+ <para>session:
+ The instance of the current session. It manages the sessions'
+ map and tables. You can set and remove the map or tables.
+ In may also get the map object. However, you should know that
+ internally it is already prepared to handle many maps.
+ Therfore, currently you would always receive a list with exactlty
+ one element. In the future, if there are more than one map,
+ you will not know which one is the currently display one and
+ therefore you should use the mainwindow as hook to find
+ the currently displayed map.
+ See Thuban/Model/session.py for the API.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ mainwindow: The mainwindow object is central to manage various
+ GUI things such as the Legend sub-window. Most notably,
+ you get access to the canvas which is the window part where
+ the map is drawn. The canvas knows, which map it currently
+ draws and therefore you get the current map via
+ context.mainwindow.canvas.Map().
+ See Thuban/UI/mainwindow.py for the API.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+ </section>
+ </chapter>
+
+ <chapter><title>Trouble Shooting</title>
+ <para>
+ Here are a few problems that users have encountered when first using Thuban.
+ </para>
+ <para>
+
+ <itemizedlist>
+ <listitem>
+ <para>After adding two or more layers nothing is drawn in the map window.
+ </para>
+ <para>
+ This is probably because the layers have different projections. Projections
+ must be set on all layers and on the map itself if the layers' projections
+ are different.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Thuban crashes on startup with the error
+ <literal>NameError: global name 'False' is not defined</literal>.
+ </para>
+ <para>
+ <varname>True</varname> and <varname>False</varname> were only introduced
+ in Python 2.2.1. Thuban depends on at least Python 2.2.1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>After compiling Thuban, Thuban crashes with an error similar to
+ <literal>
+ ImportError: /usr/local//lib/thuban/Thuban/../Lib/wxproj.so: undefined symbol: __gxx_personality_v0
+ </literal>
+ </para>
+ <para>
+ Thuban depends on the wxWindows library. If Thuban is compiled with an
+ incompatible version of the compiler than wxWindows was compiled with
+ this error may occur. Try compiling with a different version of the
+ compiler.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ If an error occurs Thuban will display a dialog indicating the error
+ before closing. The text should be copied and reported to the
+ <ulink url="http://thuban.intevation.org/bugtracker.html">
+ Intevation bugtracker
+ </ulink>.
+ More information about the system is available from
+ <menuchoice><guimenu>Help</guimenu><guimenuitem>About</guimenuitem></menuchoice> box.
+ This should also be included in the bug report.
+ <figure>
+ <title>Error Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/8_int_error.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/8_int_error.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+ </para>
+
+ </chapter>
+
+ <appendix><title>Supported Data Sources</title>
+ <para>
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>Shapefile</term>
+ <listitem>
+ <para>
+ The Shapefile format has become a standard format for saving
+ geographic vector information. It supports polygons, lines, and
+ points.
+
+ <ulink url="http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf">
+ Technical Specification.
+ </ulink>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>dBase file</term>
+ <listitem>
+ <para>
+ dBase files are used to store the attributes for each layer. This
+ is closely associated with the Shapefile format. For detailed
+ specifications on the correct format of a dBase file used with
+ Thuban please see the Technical Specification for the Shapefile
+ format above.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>PostGIS</term>
+ <listitem>
+ <para>
+ PostGIS adds support for geographic objects to the PostgreSQL
+ object-relational database. Different layer types (as for Shapefiles)
+ are supported. <ulink url="http://postgis.refractions.net">PostGIS
+ Homepage</ulink>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Raster files</term>
+ <listitem>
+ <para>
+ Binding the GDAL library Thuban supports numerous raster file formats,
+ see <ulink url="http://www.remotesensing.org/gdal/formats_list.html">
+ GDAL format list</ulink> for details.</para>
+
+ <para>Most commonly used is the <emphasis>TIFF/GeoTIFF</emphasis>
+ format: Raster maps are provided as TIFF images, with an additional
+ "world file" storing the geographic reference (usually with an
+ extension ".tfw").
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </appendix>
+
+ <appendix><title>Working with PostGIS</title>
+ <para>
+ This section focusses on the use of PostGIS in the Thuban framework. For
+ installation and maintenance of spatial databases we refer to the
+ <ulink url="http://postgis.refractions.net">PostGIS Homepage</ulink>.
+ The Thuban PostGIS support requires the
+ <ulink url="http://initd.org/software/psycopg">psycopg module</ulink>.
+ </para>
+
+ <para>
+ Working with PostGIS Databases is seperated into two steps:
+ <itemizedlist>
+ <listitem><para>Opening a Database Connection</para></listitem>
+ <listitem><para>Loading a Data Layer</para></listitem>
+ </itemizedlist>
+ </para>
+ <section><title>Opening a Database Connection</title>
+ <para>
+ Before a data layer can be loaded from a PostGIS database a
+ connection with the database has to be established.
+ <menuchoice>
+ <guimenu>Session</guimenu>
+ <guimenuitem>Database Connections ...</guimenuitem>
+ </menuchoice> opens a dialog for database connection
+ management. In the dialog new connections can be added
+ and existing ones can be removed. Removing a database
+ connection is not possible if the map still displays a
+ layer provided by this database connection.
+ </para>
+ <figure>
+ <title>Database Management Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_db_management.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_db_management.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ To add a new database connection to the session a dialog is
+ opened to specify the relevant connection data. Enter all
+ data relevant for your connection. If the connection fails
+ the dialog remains open and provides some hints on the failure.
+ </para>
+ <figure>
+ <title>Add Database Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_db_add.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_db_add.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>
+ It is important to note that information on database connections are
+ also stored with the session. Passwords are NOT stored. If you load a
+ session with database connections you are asked to enter these
+ passwords again where required.
+ </para>
+
+ </section>
+
+ <section><title>Loading a Data Layer</title>
+ <para>
+ Data layers as part of a map are loaded with the
+ <menuchoice>
+ <guimenu>Map</guimenu>
+ <guimenuitem>Add Database Layer ...</guimenuitem>
+ </menuchoice> menu item. A dialog is raised displaying two choice
+ lists. In the left list all connected databases are shown.
+ Highlighting
+ one of these and issuing a retrieval results in a list of available
+ layer tables from that database. After selection of a
+ layer the dialog is closed.
+ </para>
+ <figure>
+ <title>Add Database Dialog</title>
+ <mediaobject>
+ <imageobject><imagedata fileref="../images/app_postgis_add_layer.png" format="PNG" scale="&imgscale;"/></imageobject>
+ <imageobject><imagedata fileref="./images/app_postgis_add_layer.eps" format="EPS" scale="&imgscale;"/></imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+ </appendix>
+
+ <appendix><title>Supported Projections</title>
+ <para>
+ The following types of projections are directly support by
+ Thuban. The specific values for each are provided by the user
+ to create custom projections. Thuban comes with predefined
+ projections which are available through the Projections dialog.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>Geographic</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para>
+ <literal>Source Data</literal>: either Degrees or Radians
+ </para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Lambert Conic Conformal</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Latitude of 1st standard parallel</literal></para></listitem>
+ <listitem><para><literal>Latitude of 2nd standard parallel</literal></para></listitem>
+ <listitem><para><literal>Central Meridian</literal></para></listitem>
+ <listitem><para><literal>Latitude of Origin</literal></para></listitem>
+ <listitem><para><literal>False Easting</literal> (meters)</para></listitem>
+ <listitem><para><literal>False Northing</literal> (meters)</para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Transverse Mercator</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Latitude</literal>of origin</para></listitem>
+ <listitem><para><literal>Longitude</literal>at central meridian</para></listitem>
+ <listitem><para><literal>Scale Factor</literal>at central meridian</para></listitem>
+ <listitem><para><literal>False Easting</literal> (meters)</para></listitem>
+ <listitem><para><literal>False Northing</literal> (meters)</para></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>Universal Transverse Mercator</para>
+ <itemizedlist>
+ <listitem><para><literal>Ellipsoid</literal></para></listitem>
+ <listitem><para><literal>Zone</literal>
+ (can be guessed appling the Propose button)</para></listitem>
+ <listitem><para><literal>Southern Hemisphere</literal> flag</para></listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Thuban comes with a sample set of map projections for various
+ European countries. Apart from the basic projection they differ
+ especially in their parameterization:
+ </para>
+ <itemizedlist>
+ <listitem><para>Belgium Datum 1972 (Lambert Conic Conformal)</para>
+ </listitem>
+
+ <listitem><para>Gauss-Boaga Zone 1 (Italy, Transverse Mercartor)</para>
+ </listitem>
+
+ <listitem><para>Gauss-Krueger Zone 2 (Germany, Transverse Mercartor)
+ </para>
+ </listitem>
+
+ <listitem><para>Reseau Geodesique Francaise
+ (France, Lambert Conic Conformal)</para>
+ </listitem>
+
+ <listitem><para>UK National Grid (United Kingdom, Transverse Mercartor)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Thuban uses the comprehensive PROJ library for projections. PROJ provides
+ more than the four commonly used projections described above. If needed
+ Thuban can be easily extended to a new projection covered by PROJ.
+ </para>
+ </appendix>
+
+</book>
+
Added: packages/thuban/branches/upstream/current/Doc/technotes/README
===================================================================
--- packages/thuban/branches/upstream/current/Doc/technotes/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/technotes/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,21 @@
+Readme for Thuban's Doc/devnotes
+================================
+Author: Bernhard Herzog <bh at intevation.de>
+Last-Modified: $Date: 2004-02-26 12:22:30 +0100 (Do, 26 Feb 2004) $
+Version: $Revision: 2093 $
+
+
+Overview
+
+ This directory contains a collection of documents for Thuban
+ developers. Each file is a plain text file formatted more or less
+ like the plaintext Python PEPs [1].
+
+
+References
+
+ [1] http://python.org/peps/pep-0009.html
+ Sample Plaintext PEP Template
+
+
+
Added: packages/thuban/branches/upstream/current/Doc/technotes/coding_guidelines.txt
===================================================================
--- packages/thuban/branches/upstream/current/Doc/technotes/coding_guidelines.txt 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/technotes/coding_guidelines.txt 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,130 @@
+Title: Coding Guidelines for Thuban
+Author: Bernhard Herzog <bh at intevation.de>
+Last-Modified: $Date: 2006-04-20 15:20:48 +0200 (Do, 20 Apr 2006) $
+Version: $Revision: 2678 $
+
+
+Introduction
+
+ To keep the Thuban code maintainable all code should adhere to the
+ guidelines outlined below. The guidelines currently cover stylistic
+ issues (e.g. rules for source code formatting) as well as Python
+ programming hints and rules for using SVN and making patches.
+
+
+Source Formatting
+
+ Python and, where applicable, C/C++ source code should be formatted
+ according to these rules:
+
+ - All lines should be at most 79 characters long
+
+ - Put spaces around binary operators and after commas, colons and
+ semicolons. Do not put spaces before commas, colons and
+ semicolons and don't put them after opening or before closing
+ parentheses, brackets and braces.
+
+ - Use only spaces for indentation. Each indentation level is four
+ spaces.
+
+ - Every class, function and method should have a doc string. The
+ doc string should start with a brief one-line description of the
+ class or method. If more explanations are needed add an empty
+ line and one or more paragraphs.
+
+ - Put imports at the top of a module. Put the more fundamental
+ import statements first, and the more Thuban specific later.
+ E.g. imports from the standard library come first, then import
+ statements for third-party modules, then Thuban imports. Imports
+ from the same Thuban sub-package come last.
+
+
+Python Programming
+
+ - Thuban must remain compatible with Python 2.2.
+
+ - Do not use "from module import *"
+
+ This form of the import statement leads to code that is hard to
+ maintain for several reasons:
+
+ - When the module's contents change, the names bound in the code
+ that executes the import statement change as well and might
+ accidentally override python builtins or names already bound in
+ the module
+
+ - It's hard to find out which of the objects in the imported
+ module are actually used by the importing code. It's especially
+ hard to find out whether the import is still needed if the code
+ has changed.
+
+ - Do not check the type of parameters
+
+ Functions and methods should be coded to interfaces, not types, so
+ checking whether an object passed as a parameter to a function is
+ of a certain type or an instance of a particular class is almost
+ never a good idea.
+
+ - Use "obj is None" when testing for None not just "obj". The
+ object in question might be false without being None.
+
+ - Method names start with lower case letter.
+
+ The main reason is that we should, in the long term, adopt the more
+ common naming styles used in python code. For Thuban this basically
+ means not to start method names with upper case letters. For Thuban this
+ would be a substantial change and even though it would be easy to retain
+ the old method names for a while for backwards compatibility it's not
+ something that should be done soon. However, new classes should
+ follow this rule.
+
+Test Suite
+
+ Thuban has a fairly comprehensive test suite in the test/
+ subdirectory. The test suite is only useful if it is kept up to
+ date and if it is run often. Therefore:
+
+ - Before a checkin, run the *entire testsuite*. Yes, all of it.
+ Even if you think your change won't break anything.
+
+ - New functionality and bug fixes should have corresponding tests in
+ the test suite.
+
+ - The tests should use only public interfaces.
+
+ - Write the tests before writing the code.
+
+ - It should be possible to run the test suite without an X server
+ being present.
+
+
+SVN
+
+ - One can't say this often enough: Before a checkin, run the *entire
+ testsuite*. Yes, all of it. Even if you think your change won't
+ break anything.
+
+ - All commits should be described in the ChangeLog file. The easiest
+ way to do that is to write the ChangeLog entry first and use that
+ as the commit message. Maybe your editor has support to help with this.
+
+ - Try to make small self contained commits. In particular, if
+ during the work on a more complex change you discover a bug,
+ commit the the fix to that bug separately with a separate
+ ChangeLog entry.
+
+Patches
+
+ - When you produce patches please try to produce them as patches
+ against a current SVN version. A patch against code from a
+ tarball is often OK too but can make it more difficult to test a
+ patch if e.g. the files in SVN have changed considerably.
+
+ - Please make context diffs, i.e. use the -c or -u option of diff or svn
+ diff. The default output of diff is not suitable for a patch.
+
+ - Treat a patch like SVN commit. That is what it will end up as if
+ it is accepted, so if you want to increase the chances that it
+ will be applied, please try to make the work easier for us, and
+ make sure the test suite still works, add new tests if your patch
+ adds functionality or fixes a bug and write a ChangeLog entry.
Added: packages/thuban/branches/upstream/current/Doc/technotes/release_process.txt
===================================================================
--- packages/thuban/branches/upstream/current/Doc/technotes/release_process.txt 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/technotes/release_process.txt 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,83 @@
+Title: The Thuban Release Process
+Author: Thuban development team
+Last-Modified: $Date: 2007-02-20 10:51:07 +0000 (Di, 20 Feb 2007) $
+Version: $Revision: 2728 $
+
+How to Release a New Thuban Version
+
+ - Test Thuban until you are sure it works under the following
+ reference platforms:
+
+ Debian GNU/Linux 4.0 (aka Etch) (plus wxWindows/wxPython 2.6)
+ (Windows XP)
+
+ All test cases of stable code should pass on all platforms.
+
+ - Adjust revision number in setup.py and Thuban/version.py. See the
+ comments in version.py for details.
+
+ - Update thuban.pot and the various .po and .mo files:
+
+ cd po/
+ make pot
+ make update-po
+ make mo
+
+ See po/README for details
+
+ - Update MANIFEST.in
+
+ This is only necessary if the set of files distributed has changed
+ in such a way that the old MANIFEST.in doesn't fit anymore. This
+ could be e.g. the addition of a new top-level directory such as
+ Extensions
+
+ - Produce Source-Archives Thuban-N.N.N.tar.gz and Thuban-N.N.N.zip
+
+ python setup.py sdist
+
+
+Old:- Build a binary for W2000: Thuban-N.N.N-1.exe
+
+ On a Windows system with Inno Setup installed, unpack the source
+ archive (usually the zip file) and run:
+
+ python setup.py bdist_inno
+
+ Test the resulting setup program.
+
+Old:- Build RPMs for RedHat 7.2
+
+ Take the source tarball and, on a RedHat 7.2 system, run:
+
+ python setup.py bdist_rpm
+
+ Install the rpm and test Thuban. Make sure to have removed any
+ other Thuban rpms beforehand.
+
+ - Produce Sample-Data-Tarballs
+
+ python setup.py data_dist
+
+Old:- Tag the tested sources for CVS:
+
+ cvs tag THUBAN_N_N_N
+
+Old:- Place packages on ftp server at ftp://intevation.de/thuban/
+
+Old:- Update http://thuban.intevation.org/download.html accordingly
+
+ - Update/Extend http://thuban.intevation.org/screenshots.html
+ if there have been interesting changes/extensions to the UI.
+
+ - Make sure you closed all open issues that were solved with this
+ release.
+
+ - Write announcement including all major improvements.
+
+Old: - Send announcement to following mailing lists:
+ thuban-list at intevation.de
+ freegis-list at intevation.de
+
+ - Have a beer and thank all contributors :-)
+
Added: packages/thuban/branches/upstream/current/Doc/technotes/string_representation.txt
===================================================================
--- packages/thuban/branches/upstream/current/Doc/technotes/string_representation.txt 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Doc/technotes/string_representation.txt 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,85 @@
+Title: String Representation in Thuban
+Author: Bernhard Herzog <bh at intevation.de>
+Last-Modified: $Date: 2005-07-01 22:49:04 +0200 (Fr, 01 Jul 2005) $
+Version: $Revision: 2642 $
+
+
+Introduction
+
+ Thuban originally assumed that text is represented by byte-strings
+ encoded in ISO-8859-1 (latin-1). This is problematic when the
+ default encoding in the user's locale is not in fact latin-1, but
+ e.g. UTF-8. The solution is to use a more flexible representation
+ that will also allow the switch to Unicode as the internal string
+ representation at one point.
+
+
+Internal String Representation
+
+ Thuban has an internal string representation. All textual data read
+ by Thuban has to be converted to the internal representation. All
+ data written by Thuban has to be converted into whatever form is
+ used by the output device.
+
+ Thuban provides functions to convert between the internal
+ representation and other representations. E.g.:
+ internal_from_unicode which converts from unicode and should be used
+ when reading XML files, for instance and unicode_from_internal for
+ the conversion to Unicode.
+
+ The ultimate goal is to use Unicode objects as the internal string
+ representation. It will be much work to get there because we will
+ have to find all the places where we need to make the conversions.
+ Therefore the internal representation will be byte strings in the
+ user's default encoding.
+
+ With byte strings and especially encodings like latin-1 we can get
+ by without doing all the conversions correctly because basically all
+ byte strings are valid latin-1 strings, even if they have the wrong
+ encoding. In those cases, the text may look strange, but there
+ won't be exceptions in most cases. With Unicode objects, exceptions
+ are much more likely. And in the end it's better to see some
+ incorrect characters than no data at all.
+
+ All this boils down to the following steps:
+
+ 1. Byte-Strings as Internal Representation
+
+ The internal representation are byte strings in the user's default
+ encoding as determined by the locale. The encoding is chosen so
+ that such byte strings can be passed to wxPython without problems.
+ This even works with Unicode builds if we take care to convert the
+ translated strings (wxGetTranslation returns Unicode objects in a
+ Unicode build).
+
+ If no suitable encoding can be determined, use latin-1. It might be
+ better to use ASCII instead, but latin 1 offers somewhat better
+ backwards compatibility with older Thuban versions.
+
+ Start implementing the conversion functions and use them wherever
+ we have hard coded conversions to latin-1. It's not necessary to
+ find all places where conversion has to be done at this point.
+ Since we're using byte strings in the user's default encoding most
+ byte-strings that are read by Thuban are already in the right form
+ and in most cases it's also the right form for output.
+
+
+ 2. Implement the conversion wherever necessary
+
+ Start working toward Unicode as the internal representation. In
+ this phase, we need to find all places where conversion has to be
+ done. To help with this, there will be a command line option that
+ sets the internal representation to Unicode so that it's easy to
+ test.
+
+ The most difficult areas for this are probably the various data
+ sources. Some of them -- dbf files for instance -- q don't provide
+ any information about the encodings used.
+
+
+ 3. Switch to Unicode
+
+ Finally, switch to Unicode as the internal string representation.
+ For this step it might be best to wait until Unicode builds of
+ wxPython are the default on the common platforms.
+
Added: packages/thuban/branches/upstream/current/Examples/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Examples/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/README
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,11 @@
+Simple Example Extensions for Thuban
+------------------------------------
+
+This directory contains some simple extensions for Thuban that show how
+you can add commands and tools to Thuban.
+
+To run an examples, make sure this directory in your python path and
+import one or more of the modules in it in ~/.thuban/thubanstart.py.
+Create that file and directory if it doesn't exist yet. It is
+automatically executed by Thuban if it exists.
+
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/hello_world.py
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/hello_world.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/hello_world.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,44 @@
+# Copyright (C) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend Thuban with a sample Hello World to demonstrate simple
+extensions.
+"""
+
+__version__ = '$Revision: 2409 $'
+# $Source$
+# $Id: hello_world.py 2409 2004-11-20 21:57:14Z jan $
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+def hello_world_dialog(context):
+ """Just raise a simple dialog to greet the world.
+
+ context -- The Thuban context.
+ """
+ context.mainwindow.RunMessageBox(_('Hello World'), _('Hello World!'))
+
+
+# create a new command and register it
+registry.Add(Command('hello_world', _('Hello World'), hello_world_dialog,
+ helptext = _('Welcome everyone on this planet')))
+
+# find the extensions menu (create it anew if not found)
+examples_menu = main_menu.FindOrInsertMenu('examples', _('&Examples'))
+
+# finally bind the new command with an entry in the extensions menu
+examples_menu.InsertItem('hello_world')
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_command.py
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_command.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_command.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,60 @@
+# Copyright (C) 2002, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2002)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend thuban with a simple command.
+"""
+
+__version__ = "$Revision: 2410 $"
+# $Source$
+# $Id: simple_command.py 2410 2004-11-20 21:57:43Z jan $
+
+# First import some things we need later.
+import os
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu
+
+# a function implementing a command. Such a function is called with one
+# argument describing the context in which it is invoked. The context is
+# an object with a few public attributes for the application object, the
+# session and the main window.
+def simple_command(context):
+ print "simple_command: Application", context.application
+ print "simple_command: Session", context.session
+ print "simple_command: Main window", context.mainwindow
+ print "simple_command: Map", context.mainwindow.canvas.Map()
+
+# Add the command to the registry. A command is represented by a Command
+# instance which is instantiated with four parameters here, the name of
+# the command, it's title, the function to call when the command is
+# invoked by the user and a help text to show in the statusbar.
+#
+# The name is used internally to identify commands. The title is
+# displayed in the menus.
+registry.Add(Command("simple_command", "Simple Command", simple_command,
+ helptext = "Simple Command"))
+
+# The main menu is defined by the main_menu object in
+# Thuban.UI.mainwindow. This object has a few methods to add new menus
+# and menu items.
+#
+# FindOrInsertMenu creates a new submenu in the menu, parameters are its name
+# and title which have the same meanings as for a command. The return
+# value is a menu object for the new submenu which has the same methods
+# as main_menu.
+# If the menu already exist, this previous one will be returned an
+# no new one be created.
+menu = main_menu.FindOrInsertMenu("examples", "&Examples")
+
+# In the new menu we can add new items with InsertItem which takes the
+# name of a command as parameter or with InsertSeparator to add a
+# separator. We can also use InsertMenu to add submenus, of course. We
+# add the command twice here to demonstrate separators.
+menu.InsertItem("simple_command")
+menu.InsertSeparator()
+menu.InsertItem("simple_command")
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.py
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,109 @@
+# Copyright (C) 2002, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2002)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend thuban with a simple tool.
+"""
+
+__version__ = "$Revision: 2411 $"
+# $Source$
+# $Id: simple_tool.py 2411 2004-11-20 21:58:18Z jan $
+
+# First import some things we need later.
+import os
+from math import hypot
+from Thuban.UI.command import registry, ToolCommand
+from Thuban.UI.mainwindow import main_toolbar
+from Thuban.UI.viewport import Tool
+
+
+# A tool is a class usually derived from the Tool class. The tool class
+# provides some standard methods to handle mouse events. It maintains a
+# few instance variables that can be used when processing mouse events:
+# self.start is the point where the user started to drag, self.current
+# is the current position, self.dragging is true while the user is
+# moving the mouse with the (left) button pressed.
+
+class SimpleTool(Tool):
+
+ """A Simple Tool"""
+
+ def Name(self):
+ """Return the string 'SimpleTool'."""
+ # The return value is used to identify tools easily
+ return "SimpleTool"
+
+ def map_distance(self):
+ """Return the distance on the map between the start and current point
+ """
+ # self.view is the canvas window the tool instance is working
+ # on. Its win_to_proj method computes the coordinates in the
+ # projected map coordinates for a given point in window
+ # coordinates
+ sx, sy = apply(self.view.win_to_proj, self.start)
+ x, y = apply(self.view.win_to_proj, self.current)
+ return hypot(x - sx, y - sy)
+
+ def MouseMove(self, event):
+ """Called by the canvas window when the mouse moves"""
+ # The self.dragging flag is true, if the user is currently
+ # dragging the mouse. Code in the Tool class has already handled
+ # the button press event to set this flag.
+ if self.dragging:
+ # Call the inherited method to update some internal data
+ # (self.start, etc.)
+ Tool.MouseMove(self, event)
+ print "SimpleTool: current distance", self.map_distance()
+
+ def MouseUp(self, event):
+ if self.dragging:
+ Tool.MouseUp(self, event)
+ print "SimpleTool: final distance", self.map_distance()
+
+
+# the function implementing the "SimpleTool" command. Set the tool of
+# the canvas to SimpleTool
+def simple_tool(context):
+ canvas = context.mainwindow.canvas
+ canvas.SelectTool(SimpleTool(canvas))
+
+
+# Add the command to the registry. A command is represented by a Command
+# instance. Here it's instantiated with the the name of the command,
+# it's title and the function to call when the command is invoked by the
+# user as positional arguments. The name is used internally to identify
+# commands. The title is displayed in the menus.
+#
+# The icon keyword argument is optional and only useful if the command
+# is used in a toolbar. It should be the name of an XPM file without the
+# .xpm extension which will be automatically appended. We assume here
+# that the icon's XPM file is located in the same directory as this
+# module.
+#
+# The helptext keyword argument is an optional helptext.
+#
+# The checked keyword argument is an optional function to determine
+# whether the button or menu item should be checked. It's called with
+# the context. If the checked argument is not given the button or menu
+# item will be a normal command button/item.
+
+def check_simple_tool(context):
+ """Return if the current tool of the context is the simple tool"""
+ # the CurrentTool() method of the canvas returns the result of the
+ # tool's Name method so we just have to compare it to "SimpleTool"
+ return context.mainwindow.canvas.CurrentTool() == "SimpleTool"
+
+iconfile = os.path.abspath(os.path.join(os.path.split(__file__)[0],
+ "simple_tool"))
+registry.Add(ToolCommand("simple_tool", "Simple Tool", simple_tool,
+ icon = iconfile, helptext = "Simple Tool",
+ checked = check_simple_tool))
+
+# Add the command to the toolbar
+main_toolbar.InsertSeparator()
+main_toolbar.InsertItem("simple_tool")
Added: packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Examples/simple_extensions/simple_tool.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * measure_xpm[] = {
+"24 24 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" . ... . ",
+" . . . ",
+" ....... .. ...... ",
+" . . . ",
+" . .. . ",
+" . . ",
+" . . ",
+" .................... ",
+" . . ",
+" . . ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Extensions/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Extensions/bboxdump/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/bboxdump/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/bboxdump/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank at intevation.de> (2004)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# import the actual module
+import bboxdump
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'bboxdump',
+ version = '1.0.0',
+ authors= [ 'Frank Koormann' ],
+ copyright = '2004 Intevation GmbH',
+ desc = _("Dumps the bounding boxes of all\n" \
+ "shapes of the selected layer.")))
Added: packages/thuban/branches/upstream/current/Extensions/bboxdump/bboxdump.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/bboxdump/bboxdump.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/bboxdump/bboxdump.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,244 @@
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend thuban with a bounding box dump.
+
+Dumps the bounding boxes of all shapes of the selected layer.
+An optional column can be specified to group the objects,
+in this case the bounding box is a union of the separate boxes.
+"""
+
+__version__ = '$Revision: 2721 $'
+# $Source$
+# $Id: bboxdump.py 2721 2007-01-13 15:11:42Z dpinte $
+
+import os, sys
+import string
+
+import wx
+from wx.lib.dialogs import ScrolledMessageDialog
+
+from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu, _has_selected_shape_layer
+from Thuban import _
+
+import shapelib
+import dbflib
+
+# Widget IDs
+ID_FILENAME = 4001
+ID_ATTRIBUTES = 4002
+ID_SELFN = 4003
+
+class BBoxDumpDialog(wx.Dialog):
+ """Bounding Box Dump Dialog
+
+ Specify a filename for the dump and optionally a layer's column
+ field to group objects.
+ """
+
+ def __init__(self, parent, title, layer = None):
+ wx.Dialog.__init__(self, parent, -1, title,
+ style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
+
+ if layer is None:
+ return wx.ID_CANCEL
+
+ # Store the layer
+ self.layer = layer
+
+ # Filename selection elements
+ self.filename = wx.TextCtrl(self, ID_FILENAME, "")
+ self.button_selectfile = wx.Button(self, ID_SELFN, _('Select...'))
+ wx.EVT_BUTTON(self, ID_SELFN, self.OnSelectFilename)
+
+ # Column choice elements
+ self.choice_column = wx.Choice(self, ID_ATTRIBUTES)
+ self.choice_column.Append(_('Select...'), None)
+ for col in self.layer.ShapeStore().Table().Columns():
+ self.choice_column.Append(col.name, col)
+ self.choice_column.SetSelection(0)
+
+ # Dialog button elements
+ self.button_dump = wx.Button(self, wx.ID_OK, _("OK"))
+ wx.EVT_BUTTON(self, wx.ID_OK, self.OnDump)
+ self.button_dump.SetDefault()
+ # TODO: Disable the OK button until a filename is entered ...
+ # self.button_dump.Enable(False)
+ self.button_cancel = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+
+
+ # Dialog Layout: three horizontal box sizers.
+ topbox = wx.BoxSizer(wx.VERTICAL)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ topbox.Add(hbox, 0, wx.ALL|wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, _("File:")),
+ 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ hbox.Add(self.filename, 1, wx.ALL|wx.EXPAND, 4)
+ hbox.Add(self.button_selectfile, 0, wx.ALL, 4)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ topbox.Add(hbox, 0, wx.ALL|wx.EXPAND)
+ hbox.Add(wx.StaticText(self, -1, _("Group by:")),
+ 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ hbox.Add(self.choice_column, 1, wx.ALL|wx.EXPAND, 4)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ topbox.Add(hbox, 0, wx.ALL|wx.EXPAND)
+ hbox.Add(self.button_dump, 0, wx.ALL|wx.ALIGN_CENTER,
+ 10)
+ hbox.Add(self.button_cancel, 0, wx.ALL|wx.ALIGN_CENTER,
+ 10)
+
+ # Finalize ...
+ self.SetAutoLayout(True)
+ self.SetSizer(topbox)
+ topbox.Fit(self)
+ topbox.SetSizeHints(self)
+
+ # Store for later use
+ self.parent = parent
+
+ def OnDump(self, event):
+ """Bounding Box Dump Dialog event handler OK button.
+
+ Prepare the inputs from the dialog and call processing.
+ """
+ i = self.choice_column.GetSelection()
+ column = self.choice_column.GetClientData(i)
+ self.Close()
+
+ ThubanBeginBusyCursor()
+ try:
+ bboxmessage = bboxdump(self.layer, column, self.filename.GetValue())
+ finally:
+ ThubanEndBusyCursor()
+
+ if bboxmessage:
+ dlg = ScrolledMessageDialog(
+ self.parent, bboxmessage,
+ _("Bounding Box Dump %s") % self.layer.Title())
+ dlg.ShowModal()
+
+ def OnSelectFilename(self, event):
+ """Bounding Box Dump Dialog event handler File Selection.
+
+ Opens a file dialog to specify a file to dump into.
+ """
+ dlg = wx.FileDialog(self, _("Dump Bounding Boxes To"),
+ os.path.dirname(self.filename.GetValue()),
+ os.path.basename(self.filename.GetValue()),
+ _("CSV Files (*.csv)|*.csv|") +
+ _("All Files (*.*)|*.*"),
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.filename.SetValue(dlg.GetPath())
+ dlg.Destroy()
+ else:
+ dlg.Destroy()
+
+
+def bboxdump(layer, column, filename):
+ """Bounding Box Dump Processing
+
+ layer - Layer of shapes to be dumped
+ column - optional column to group shapes (else None)
+ filename - optional filename to dump into (else empty string, i.e. dump
+ to message dialog)
+ """
+ # Preparation
+ shapelist = {}
+ bboxmessage = []
+
+ dlg= wx.ProgressDialog(_("Bounding Box Dump"),
+ _("Collecting shapes ..."),
+ layer.ShapeStore().NumShapes(),
+ None)
+
+ cnt = 0
+ step = int(layer.ShapeStore().NumShapes() / 100.0)
+ if step == 0:
+ step = 1
+
+ # Collect shape ids to be dumped
+ if column is None:
+ # A simple dump of shapes bbox is required
+ for s in layer.ShapeStore().AllShapes():
+ i = s.ShapeID()
+ shapelist[i] = (i,)
+ if cnt % step == 0:
+ dlg.Update(cnt)
+ cnt = cnt + 1
+ else:
+ # group them by column ...
+ for s in layer.ShapeStore().AllShapes():
+ i = s.ShapeID()
+ row = layer.ShapeStore().Table().ReadRowAsDict(i)
+ att = row[column.name]
+ if not shapelist.has_key(att):
+ shapelist[att] = []
+ shapelist[att].append(i)
+ if cnt % step == 0:
+ dlg.Update(cnt)
+ cnt = cnt + 1
+
+ dlg.Destroy()
+ dlg= wx.ProgressDialog(_("Bounding Box Dump"),
+ _("Dump bounding boxes of selected shapes ..."),
+ len(shapelist),
+ None)
+ cnt = 0
+ step = int(len(shapelist) / 100.0)
+ if step == 0:
+ step = 1
+
+ # Dump them, sorted
+ keys = shapelist.keys()
+ keys.sort()
+ for key in keys:
+ bbox = layer.ShapesBoundingBox(shapelist[key])
+ bboxmessage.append("%.3f,%.3f,%.3f,%.3f,%s\n" % (
+ bbox[0], bbox[1], bbox[2], bbox[3], key))
+ if cnt % step == 0:
+ dlg.Update(cnt)
+ cnt = cnt + 1
+ dlg.Destroy()
+
+ # finally
+ if filename != '':
+ bboxfile = file(filename, 'w+')
+ bboxfile.write(string.join(bboxmessage))
+ bboxfile.close()
+ return None
+ else:
+ return string.join(bboxmessage)
+
+def LayerBBoxDump(context):
+ """Menu Handler BBoxDump
+ """
+ layer = context.mainwindow.canvas.SelectedLayer()
+ if layer is not None:
+ dlg = BBoxDumpDialog(context.mainwindow, _("Bounding Box Dump"),
+ layer = layer)
+ dlg.ShowModal()
+
+
+# bboxdump executed as an extension to Thuban
+
+# register the new command
+registry.Add(Command('bboxdump', _('BBox Dump'), LayerBBoxDump,
+ helptext = _('Dump Bounding Boxes of Layer Objects'),
+ sensitive = _has_selected_shape_layer))
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally add the new entry to the extensions menu
+extensions_menu.InsertItem('bboxdump')
Added: packages/thuban/branches/upstream/current/Extensions/drawshape/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/drawshape/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/drawshape/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,47 @@
+Draw Shape Extension for Thuban
+===============================
+
+
+ *** Warning: ***
+
+ This extension is very experimental and may corrupt your data. Use at
+ your own peril.
+
+ The installation instructions here are very brief to make it more
+ likely that people who use it know what they're doing.
+
+
+
+Summary
+-------
+
+This extension for Thuban allows you do add shapes to shapefiles.
+
+
+
+Installation
+------------
+
+1. Apply the patch in patch.diff
+
+2. Put the drawshape.py somewhere where you can import it from
+ ~/.thuban/thubanstart.py and add the appropriate import statement to
+ thuban/thubanstart.py
+
+
+Usage
+-----
+
+The extension adds a new icon to the toolbar. This icon is the same as
+the one for the identify tool because there wasn't time to create a new
+one :)
+
+To add a shape, select the layer you want to add to, activate the tool
+and draw the shape by clicking on the map where the vertices should be
+with the left mouse button. When done, click the right button and the
+shape will be added to the shapefile with a set of default attributes
+(zeros and empty strings).
+
+The layer must be a layer displaying a shapefile with polygons (arcs and
+points are not supported) and the associated table must be a real dbf
+file and not e.g. a joined table.
Added: packages/thuban/branches/upstream/current/Extensions/drawshape/drawshape.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/drawshape/drawshape.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/drawshape/drawshape.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,155 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Extension to draw polygons
+
+*** Warning: ***
+
+This extension is very experimental and may corrupt your data. Use at
+your own peril.
+"""
+
+__version__ = "$Revision: 2207 $"
+# $Source$
+# $Id: drawshape.py 2207 2004-05-16 09:30:34Z jan $
+
+
+import os
+
+from wxPython.wx import *
+
+import shapelib
+import Thuban
+from Thuban import _
+from Thuban.Model.data import SHAPETYPE_POLYGON
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_STRING, \
+ FIELDTYPE_DOUBLE
+from Thuban.UI.command import registry, ToolCommand
+from Thuban.UI.mainwindow import main_menu, main_toolbar
+from Thuban.UI.viewport import Tool
+
+
+def write_empty_row(table, row):
+ """Write an empty record to the row
+
+ The values in the record will be set to suitable default values
+ depending on the type: 0 for numeric types and the empty string for
+ strings.
+ """
+ values = {}
+ for col in table.Columns():
+ if col.type == FIELDTYPE_INT:
+ value = 0
+ elif col.type == FIELDTYPE_DOUBLE:
+ value = 0.0
+ elif col.type == FIELDTYPE_STRING:
+ value = ""
+ else:
+ print "write_empty_row: Unhandled col.type", col.type
+ values[col.name] = value
+ table.write_record(row, values)
+
+
+def write_shape(shapestore, points):
+ """Addd the points as a new shape to the shapestore
+
+ The points argument should be a list of the same structure as that
+ returned by the shapelib bindings for a polygon. It is passed
+ directly to the SHPObject constructor.
+ """
+ shapefile = shapelib.ShapeFile(shapestore.FileName(), "r+b")
+ obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1, points)
+ newid = shapefile.write_object(-1, obj)
+ write_empty_row(shapestore.Table(), newid)
+ shapefile.close()
+ shapestore._open_shapefile()
+
+
+class ShapeDrawTool(Tool):
+
+ def __init__(self, view):
+ Tool.__init__(self, view)
+ self.points = []
+
+ def Name(self):
+ return "ShapeDrawTool"
+
+ def find_shapestore(self):
+ """Return the shapestore into which to write and the projection
+
+ If the currently selected layer is a layer with polygons return
+ a tuple of the shapestore and the layer's projection.
+ Otherwise return a tuple of Nones.
+ """
+ layer = self.view.SelectedLayer()
+ if layer is not None and layer.HasShapes() \
+ and layer.ShapeType() == SHAPETYPE_POLYGON:
+ return layer.ShapeStore(), layer.GetProjection()
+ return None, None
+
+ def MouseDown(self, event):
+ Tool.MouseDown(self, event)
+ if event.RightDown():
+ map_proj = self.view.Map().GetProjection()
+ shapestore, proj = self.find_shapestore()
+ if shapestore is not None and len(self.points) > 2:
+ points = self.points[:]
+ if map_proj is not None:
+ points = [tuple(map_proj.Inverse(*p)) for p in points]
+ if proj is not None:
+ points = [tuple(proj.Forward(*p)) for p in points]
+ points.append(points[0])
+ write_shape(shapestore, [points])
+ self.points = []
+ self.view.full_redraw()
+ else:
+ if not self.points:
+ self.points.append(self.view.win_to_proj(*self.current))
+
+ def MouseUp(self, event):
+ Tool.MouseUp(self, event)
+ self.points.append(self.view.win_to_proj(*self.current))
+
+ def draw(self, dc):
+ points = [self.view.proj_to_win(*p) for p in self.points] \
+ + [self.current]
+ if len(points) == 2:
+ dc.DrawLines(points)
+ else:
+ dc.DrawPolygon(points)
+
+ def DrawPermanent(self, dc):
+ dc.SetPen(wxPen(wxColor(255, 128, 0), 2))
+ dc.SetBrush(wxTRANSPARENT_BRUSH)
+ dc.DrawPolygon([self.view.proj_to_win(*p) for p in self.points])
+
+
+def shape_draw_tool(context):
+ canvas = context.mainwindow.canvas
+ canvas.SelectTool(ShapeDrawTool(canvas))
+
+def check_shape_draw_tool(context):
+ return context.mainwindow.canvas.CurrentTool() == "ShapeDrawTool"
+
+
+iconfile = os.path.join(os.path.abspath(Thuban.__path__[0]),
+ "..", "Resources", "Bitmaps", "identify")
+registry.Add(ToolCommand("shape_draw_tool", "Shape Draw Tool",
+ shape_draw_tool, icon = iconfile,
+ helptext = "Draw a shape",
+ checked = check_shape_draw_tool))
+
+# Add the command to the toolbar
+main_toolbar.InsertSeparator()
+main_toolbar.InsertItem("shape_draw_tool")
+
+# find the experimental menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu('experimental',
+ _('Experimenta&l'))
+
+# finally add the new command to the experimental menu
+experimental_menu.InsertItem('shape_draw_tool')
Added: packages/thuban/branches/upstream/current/Extensions/drawshape/patch.diff
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/drawshape/patch.diff 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/drawshape/patch.diff 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,87 @@
+Index: Thuban/UI/view.py
+===================================================================
+RCS file: /thubanrepository/thuban/Thuban/UI/view.py,v
+retrieving revision 1.59
+diff -c -r1.59 view.py
+*** Thuban/UI/view.py 27 Oct 2003 13:01:58 -0000 1.59
+--- Thuban/UI/view.py 25 Nov 2003 13:10:15 -0000
+***************
+*** 128,133 ****
+--- 128,134 ----
+ EVT_PAINT(self, self.OnPaint)
+ EVT_LEFT_DOWN(self, self.OnLeftDown)
+ EVT_LEFT_UP(self, self.OnLeftUp)
++ wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
+ EVT_MOTION(self, self.OnMotion)
+ EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
+ wx.EVT_SIZE(self, self.OnSize)
+***************
+*** 140,145 ****
+--- 141,150 ----
+ def PreviewBitmap(self):
+ return self.bitmap
+
++ def SelectTool(self, tool):
++ ViewPort.SelectTool(self, tool)
++ self.redraw()
++
+ def PanTool(self):
+ """Start the canvas pan tool"""
+ self.SelectTool(CanvasPanTool(self))
+***************
+*** 170,175 ****
+--- 175,182 ----
+ dc.DrawBitmap(self.bitmap, 0, 0)
+ if self.selection_bitmap is not None:
+ dc.DrawBitmap(self.selection_bitmap, 0, 0, True)
++ if self.tool is not None:
++ self.tool.DrawPermanent(dc)
+ dc.EndDrawing()
+ else:
+ # If we've got no map or if the map is empty, simply clear
+***************
+*** 384,389 ****
+--- 391,400 ----
+ self.drag_dc = None
+ self.dragging = 0
+ self.MouseLeftUp(event)
++ self.redraw()
++
++ def OnRightDown(self, event):
++ self.MouseRightDown(event)
+
+ def OnMotion(self, event):
+ if self.dragging:
+Index: Thuban/UI/viewport.py
+===================================================================
+RCS file: /thubanrepository/thuban/Thuban/UI/viewport.py,v
+retrieving revision 1.15
+diff -c -r1.15 viewport.py
+*** Thuban/UI/viewport.py 6 Oct 2003 17:31:31 -0000 1.15
+--- Thuban/UI/viewport.py 25 Nov 2003 13:10:15 -0000
+***************
+*** 80,85 ****
+--- 80,88 ----
+ def draw(self, dc):
+ pass
+
++ def DrawPermanent(self, dc):
++ pass
++
+ def MouseDown(self, event):
+ self.drag_start(event.m_x, event.m_y)
+
+***************
+*** 598,603 ****
+--- 601,611 ----
+ self.set_current_position(event)
+ if self.tool is not None:
+ self.tool.MouseUp(event)
++
++ def MouseRightDown(self, event):
++ self.set_current_position(event)
++ if self.tool is not None:
++ self.tool.MouseDown(event)
+
+ def MouseMove(self, event):
+ self.set_current_position(event)
Added: packages/thuban/branches/upstream/current/Extensions/export_shapefile/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/export_shapefile/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/export_shapefile/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,23 @@
+# Copyright (c) 2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+def init():
+ """Initialize storeshape extension module."""
+ import export_shapefile
+ return None
+
+ext_registry.add(ExtensionDesc(
+ name = 'export_shapefile',
+ version = '0.1.0',
+ authors= [ 'Jan-Oliver Wagner' ],
+ copyright = '2005 Intevation GmbH',
+ desc = _("Exports the selected layer as a Shapefile."),
+ init_callback = init))
Added: packages/thuban/branches/upstream/current/Extensions/export_shapefile/export_shapefile.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/export_shapefile/export_shapefile.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/export_shapefile/export_shapefile.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,98 @@
+# Copyright (C) 2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend Thuban with a routine to export a layer
+as a Shapefile.
+"""
+
+__version__ = '$Revision: 2724 $'
+# $Source$
+# $Id: export_shapefile.py 2724 2007-02-20 10:25:11Z bernhard $
+
+import wx
+
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
+ SHAPETYPE_POINT
+from Thuban.Model.table import table_to_dbf
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu
+from Thuban import _
+
+import shapelib
+
+def ExportLayerAsShapefile(context):
+ """Request filename from user,
+ and create the Shapefile(s) .shp, .dbf and .shx.
+
+ context -- The Thuban context.
+ """
+ # First, find the current layer
+ layer = context.mainwindow.canvas.SelectedLayer()
+ if layer is None:
+ context.mainwindow.RunMessageBox(_('Export Shapefile'),
+ _('No layer selected'))
+ return
+
+ # Second, get the basefilename for the shapefile.
+ dlg = wx.FileDialog(context.mainwindow,
+ _('Export Shapefile'), '.', '',
+ _('Shapefile Files (*.shp)|*.shp|'),
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()[:-4]
+ dlg.Destroy()
+ else:
+ return
+
+ # Third, create the dbf file of the new Shapefile
+ dbf_filename = filename + '.dbf'
+ if hasattr(layer, "ShapeStore"):
+ table = layer.ShapeStore().Table()
+ table_to_dbf(table, dbf_filename)
+
+ # Fourth, prepare the shp file of the new Shapefile
+ shp_filename = filename + '.shp'
+ shapetypes = { SHAPETYPE_POLYGON: shapelib.SHPT_POLYGON,
+ SHAPETYPE_ARC: shapelib.SHPT_ARC,
+ SHAPETYPE_POINT: shapelib.SHPT_POINT}
+ shp = shapelib.create(shp_filename, shapetypes[layer.ShapeType()])
+
+ # Now go through all shapes and store them to the file
+ dlg= wx.ProgressDialog(_("Export Shapefile"),
+ _("Storing shapes ..."),
+ layer.ShapeStore().NumShapes(),
+ None)
+
+ cnt = 0
+ step = int(layer.ShapeStore().NumShapes() / 100.0)
+ if step == 0: step = 1
+
+ for s in layer.ShapeStore().AllShapes():
+ i = s.ShapeID()
+ print s.Points()
+ obj = shapelib.SHPObject(shapetypes[layer.ShapeType()], i, s.Points())
+ shp.write_object(i, obj)
+ if cnt % step == 0:
+ dlg.Update(cnt)
+ cnt = cnt + 1
+
+ del shp
+ dlg.Destroy()
+
+
+# register the new command
+registry.Add(Command('ExportShapefile', _('Export Layer as Shapefile ...'),
+ ExportLayerAsShapefile,
+ helptext = _('Export the active layer as a Shapefile')))
+
+# find the experimental menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu("experimental", \
+ _("Experimenta&l"))
+
+# finally add the new entry to the extensions menu
+experimental_menu.InsertItem('ExportShapefile')
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,25 @@
+# Copyright (c) 2003-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003-2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+def init():
+ """Initialize gns2shp extension module."""
+ import gns2shp
+ return None
+
+ext_registry.add(ExtensionDesc(
+ name = 'gns2shp',
+ version = '1.0.0',
+ authors= [ 'Jan-Oliver Wagner' ],
+ copyright = '2003, 2004 Intevation GmbH',
+ desc = _("Converts GNS (Geographical Name Service\n" \
+ "of NIMA) to Shapefile format and\n" \
+ "displays the data."),
+ init_callback = init))
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/gns2shp.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/gns2shp.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/gns2shp.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,185 @@
+# Copyright (C) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Extend thuban with a gns2shp converter.
+
+This module also works without Thuban on the command line
+if the shapelib and dbflib python wrappers can be found via the
+PYTHONPATH (e.g. via including directory 'Lib' of thuban directory).
+
+The GUI should eventually be extended to allow pre-selection
+of the points to import in order to reduce immense quantities
+of some country files.
+"""
+
+__version__ = '$Revision: 2721 $'
+# $Source$
+# $Id: gns2shp.py 2721 2007-01-13 15:11:42Z dpinte $
+
+import os, sys
+
+# only import GUI and register when not called as command line tool
+if __name__ != '__main__':
+ import wx
+
+ from Thuban.UI.command import registry, Command
+ from Thuban.UI.mainwindow import main_menu
+ from Thuban import _
+ from Thuban.Model.layer import Layer
+
+import shapelib
+import dbflib
+
+def gns2shp(src_fname, dest_fname):
+ """Convert a file from gns textformat into a Shapefile.
+
+ The GNS text format is described on
+ http://www.nima.mil/gns/html/gis.html
+
+ src_fname -- Filename of the GNS standard textfile (including suffix '.txt)
+ dest_fname -- Filename where to write the Shapefile components (name
+ without suffix). After successful completion there
+ will be files "dest_fname".shp, "dest_fname".shx and
+ "dest_fname.dbf".
+
+ Return: Number of sucessfully converted entries
+ """
+ gns_filename = src_fname
+ shp_filename = dest_fname + '.shp'
+ dbf_filename = dest_fname + '.dbf'
+
+ gns = open(gns_filename, 'r').readlines()
+
+ shp = shapelib.create(shp_filename, shapelib.SHPT_POINT)
+ dbf = dbflib.create(dbf_filename)
+ dbf.add_field('RC', dbflib.FTInteger, 1, 0)
+ dbf.add_field('UFI', dbflib.FTInteger, 10, 0)
+ dbf.add_field('UNI', dbflib.FTInteger, 10, 0)
+ dbf.add_field('UTM', dbflib.FTString, 4, 0)
+ dbf.add_field('JOG', dbflib.FTString, 7, 0)
+ dbf.add_field('FC', dbflib.FTString, 1, 0)
+ dbf.add_field('DSG', dbflib.FTString, 5, 0)
+ dbf.add_field('PC', dbflib.FTInteger, 1, 0)
+ dbf.add_field('CC1', dbflib.FTString, 2, 0)
+ dbf.add_field('ADM1', dbflib.FTString, 2, 0)
+ dbf.add_field('ADM2', dbflib.FTString, 200, 0)
+ dbf.add_field('DIM', dbflib.FTInteger, 10, 0)
+ dbf.add_field('CC2', dbflib.FTString, 2, 0)
+ dbf.add_field('NT', dbflib.FTString, 1, 0)
+ dbf.add_field('LC', dbflib.FTString, 2, 0)
+ dbf.add_field('SHORT_FORM', dbflib.FTString, 128, 0)
+ dbf.add_field('GENERIC', dbflib.FTString, 128, 0)
+ dbf.add_field('SORT_NAME', dbflib.FTString, 200, 0)
+ dbf.add_field('FULL_NAME', dbflib.FTString, 200, 0)
+ dbf.add_field('FULL_ND', dbflib.FTString, 200, 0) # FULL_NAME_ND
+ dbf.add_field('MODIFY_DATE', dbflib.FTString, 11, 0)
+ del dbf
+ dbf = dbflib.open(dbf_filename, 'r+b')
+
+ gns.pop(0) # drop the header line
+
+ i = 0
+ for line in gns:
+ if line[0] == '#': continue
+ RC, UFI, UNI, DD_LAT, DD_LONG, DMS_LAT, DMS_LONG, UTM, \
+ JOG, FC, DSG, PC, CC1, ADM1, ADM2, DIM, CC2, NT, LC, \
+ SHORT_FORM, GENERIC, SORT_NAME, FULL_NAME, FULL_NAME_ND, \
+ MODIFY_DATE = line.split('\t')
+ RC = int(RC)
+ UFI = int(UFI)
+ UNI = int(UNI)
+ DD_LAT = float(DD_LAT)
+ DD_LONG = float(DD_LONG)
+ try: PC = int(PC)
+ except: PC = None
+ try: DIM = int(DIM)
+ except: DIM = None
+ MODIFY_DATE = MODIFY_DATE[0:10] # kill trailing "\n" or "\r\n"
+ obj = shapelib.SHPObject(shapelib.SHPT_POINT, i, [[(DD_LONG, DD_LAT)]])
+ shp.write_object(-1, obj)
+ dbf.write_record(i, { 'RC': RC, 'UFI': UFI, 'UNI': UNI, 'UTM': UTM,
+ 'JOG': JOG, 'FC': FC, 'DSG': DSG, 'PC': PC,
+ 'CC1': CC1, 'ADM1': ADM1, 'ADM2': ADM2,
+ 'DIM': DIM, 'CC2': CC2, 'NT': NT, 'LC': LC,
+ 'SHORT_FORM': SHORT_FORM, 'GENERIC': GENERIC,
+ 'SORT_NAME': SORT_NAME, 'FULL_NAME': FULL_NAME,
+ 'FULL_ND': FULL_NAME_ND,
+ 'MODIFY_DAT': MODIFY_DATE})
+ i += 1
+
+ del shp
+ del dbf
+
+ return i
+
+def gns2shp_dialog(context):
+ """Request filename from user, run conversion and add
+ resulting shapefile to the current map.
+
+ context -- The Thuban context.
+ """
+ dlg = wx.FileDialog(context.mainwindow,
+ _('Select GNS file'), '.', '',
+ _('Generate Files (*.txt)|*.txt|') +
+ _('All Files (*.*)|*.*'),
+ wx.OPEN|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ gns_filename = dlg.GetPath()
+ dlg.Destroy()
+ else:
+ return
+
+ no = gns2shp(gns_filename, gns_filename[:-4])
+ if no <= 0:
+ context.mainwindow.RunMessageBox(_('gns2shp'), _('Conversion failed'))
+ return
+ else:
+ context.mainwindow.RunMessageBox(_('gns2shp %s') % __version__,
+ _('%d locations converted' % no))
+
+ # Now load the newly created shapefile
+ filename = gns_filename[:-4] + '.shp'
+ title = os.path.splitext(os.path.basename(filename))[0]
+ map = context.mainwindow.canvas.Map()
+ has_layers = map.HasLayers()
+ try:
+ store = context.session.OpenShapefile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(_('Add GNS Layer'),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ layer = Layer(title, store)
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ context.mainwindow.canvas.FitMapToWindow()
+
+if __name__ == '__main__': # gns2shp executed as a command line tool
+ print 'gns2shp.py %s' % __version__
+ if len(sys.argv) == 3:
+ no = gns2shp(sys.argv[1], sys.argv[2][:-4])
+ print '%d locations converted' % no
+ sys.exit(0)
+ else:
+ print 'usage: gns2shp.py GNS-file Shapefile'
+ sys.exit(1)
+
+
+# gns2shp executed as an extension to Thuban
+
+# register the new command
+registry.Add(Command('gns2shp', _('gns2shp...'), gns2shp_dialog,
+ helptext = _('Convert GNS-file into a shapefile')))
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally add the new entry to the extensions menu
+extensions_menu.InsertItem('gns2shp')
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/test/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/test/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/test/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,10 @@
+This directory contains tests of the gns2shl extension.
+
+About file "ls.txt":
+
+LIECHTENSTEIN LS 2002-11-08 1999-01 1988-01 3
+retrieved from:
+http://www.nima.mil/gns/html/cntry_files.html
+
+Run test with:
+python test_gns2shp.py
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/test/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/test/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/test/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/test/ls.txt
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/test/ls.txt 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/test/ls.txt 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,89 @@
+RC UFI UNI DD_LAT DD_LONG DMS_LAT DMS_LONG UTM JOG FC DSG PC CC1 ADM1 ADM2 DIM CC2 NT LC SHORT_FORM GENERIC SORT_NAME FULL_NAME FULL_NAME_ND MODIFY_DATE
+1 -1187145 -1749126 47.0666667 9.5000000 470400 93000 NT31 NL32-02 A ADM1 LS 00 N BALZERS Balzers Balzers 1993-12-22
+1 -1187146 -1749127 47.0666667 9.5000000 470400 93000 NT31 NL32-02 P PPL LS 00 N BALZERS Balzers Balzers 1993-12-22
+1 -1187147 -1749128 47.2166667 9.5000000 471300 93000 NT32 NL32-02 P PPL LS 00 N BENDERN Bendern Bendern 1993-12-22
+1 -1187148 -1749129 47.0666667 9.6166667 470400 93700 NT41 NL32-02 T PASS LS 00 N BETTLERJOCH Bettlerjoch Bettlerjoch 1993-12-22
+1 -1187170 -1749130 47.1833333 9.5333333 471100 93200 NT42 NL32-02 P PPL LS 00 V BLANKEN Blanken Blanken 1993-12-22
+1 -1187149 -1749131 47.1666667 9.5500000 471000 93300 NT42 NL32-02 T MTS LS 00 N DREISCHWESTERN Drei Schwestern Drei Schwestern 1993-12-22
+1 -1187149 -1749132 47.1666667 9.5500000 471000 93300 NT42 NL32-02 T MTS LS 00 V DREYSCHWESTERN Drey Schwestern Drey Schwestern 1993-12-22
+1 419575 535546 47.1500000 9.5166667 470900 93100 NT32 NL32-02 P PPL LS 00 V EBAHOLZ Ebaholz Ebaholz 1999-01-26
+1 419575 535575 47.1500000 9.5166667 470900 93100 NT32 NL32-02 P PPL LS 00 N EBENHOLZ Ebenholz Ebenholz 1999-01-26
+1 -1187152 -1749133 47.0500000 9.5666667 470300 93400 NT41 NL32-02 T MT LS 00 V ENDERLINHORN Enderlin Horn Enderlin Horn 1993-12-22
+1 -1187150 -1749134 47.2166667 9.5166667 471300 93100 NT32 NL32-02 A ADM1 LS 00 N ESCHEN Eschen Eschen 1993-12-22
+1 -1187151 -1749135 47.2166667 9.5166667 471300 93100 NT32 NL32-02 P PPL LS 00 N ESCHEN Eschen Eschen 1993-12-22
+1 -1187150 -1749136 47.2166667 9.5166667 471300 93100 NT32 NL32-02 A ADM1 LS 00 V ESCHENNEDELN Eschen-Nedeln Eschen-Nedeln 1993-12-22
+1 -1187152 -1749137 47.0500000 9.5666667 470300 93400 NT41 NL32-02 T MT LS 00 N FALKNIS Falknis Falknis 1993-12-22
+1 -1187152 -1749138 47.0500000 9.5666667 470300 93400 NT41 NL32-02 T MT LS 00 V FALKNISHORN Falknis Horn Falknis Horn 1993-12-22
+1 -1187153 -1749139 47.2000000 9.5833333 471200 93500 NT42 NL32-02 T MT LS 00 N FRASTANZERSAND Frastanzer Sand Frastanzer Sand 1993-12-22
+1 -1187154 -1749140 47.1333333 9.5500000 470800 93300 NT42 NL32-02 T MT LS 00 N FURSTENSTEIG Fürstensteig Furstensteig 1993-12-22
+1 419573 535544 47.1333333 9.5333333 470800 93200 NT42 NL32-02 P PPL LS 00 N GAFLEI Gaflei Gaflei 1999-01-26
+1 -1187155 -1749141 47.1500000 9.6166667 470900 93700 NT42 NL32-02 T MT LS 00 N GALLINAKOPF Gallinakopf Gallinakopf 1993-12-22
+1 -1187157 -1749142 47.2166667 9.5000000 471300 93000 NT32 NL32-02 P PPL LS 00 V GAMBRIN Gambrin Gambrin 1993-12-22
+1 -1187156 -1749143 47.2166667 9.5000000 471300 93000 NT32 NL32-02 A ADM1 LS 00 N GAMPRIN Gamprin Gamprin 1993-12-22
+1 -1187157 -1749144 47.2166667 9.5000000 471300 93000 NT32 NL32-02 P PPL LS 00 N GAMPRIN Gamprin Gamprin 1993-12-22
+1 -1187156 -1749145 47.2166667 9.5000000 471300 93000 NT32 NL32-02 A ADM1 LS 00 V GAMPRINBENDERN Gamprin-Bendern Gamprin-Bendern 1993-12-22
+1 -1187158 -1749146 47.1666667 9.5666667 471000 93400 NT42 NL32-02 T MT LS 00 N GARSELLAKOPF Garsellakopf Garsellakopf 1993-12-22
+1 -1187160 -1749147 47.0500000 9.5833333 470300 93500 NT41 NL32-02 T PK LS 00 V GRAUSPITZ Grauspitz Grauspitz 1993-12-22
+1 -1187192 -1749148 47.0500000 9.5833333 470300 93500 NT41 NL32-02 T PK LS 00 V GRAUSPITZ Grauspitz Grauspitz 1993-12-22
+1 -1187159 -1749149 47.2333333 9.5333333 471400 93200 NT43 NL32-02 P PPLX LS 00 N HINTERERSCHELLENBERG Hinterer Schellenberg Hinterer Schellenberg 1993-12-22
+1 -1187160 -1749150 47.0500000 9.5833333 470300 93500 NT41 NL32-02 T PK LS 00 N HINTERGRAUSPITZ Hinter-Grauspitz Hinter-Grauspitz 1993-12-22
+1 419566 535536 47.0500000 9.5500000 470300 93300 NT41 NL32-02 T VAL LS 00 N LAWENA Lawena Lawena 1999-01-26
+1 -1187161 -1749151 47.1666667 9.5333333 471000 93200 NT42 NL32-02 A PCLI LS 00 V LICHTENSTEIN Lichtenstein Lichtenstein 1996-11-29
+1 -1187161 -1749152 47.1666667 9.5333333 471000 93200 NT42 NL32-02 A PCLI LS 00 V LIECHTENSTEIN Liechtenstein Liechtenstein 1996-11-29
+1 -1187161 -1749154 47.1666667 9.5333333 471000 93200 NT42 NL32-02 A PCLI LS 00 N GM Liechtenstein Fürstentum LIECHTENSTEIN FURSTENTUM Fürstentum Liechtenstein Furstentum Liechtenstein 1996-11-29
+1 -1187161 -1749153 47.1666667 9.5333333 471000 93200 NT42 NL32-02 A PCLI LS 00 C Liechtenstein LIECHTENSTEIN PRINCIPALITYOF Principality of Liechtenstein Principality of Liechtenstein 1996-11-29
+1 419565 535533 47.0500000 9.5000000 470300 93000 NT31 NL32-02 P PPL LS 00 N MALS Mäls Mals 1999-01-26
+1 419572 535543 47.1333333 9.5333333 470800 93200 NT42 NL32-02 P PPL LS 00 N MASESCHA Masescha Masescha 1999-01-26
+1 -1187162 -1749155 47.1333333 9.6166667 470800 93700 NT42 NL32-02 T PASS LS 00 V MATLAJOCH Matla Joch Matla Joch 1994-04-28
+1 -1187162 -1749159 47.1333333 9.6166667 470800 93700 NT42 NL32-02 T PASS LS 00 AU N MATLERJOCH Matlerjoch Matlerjoch 1994-04-28
+1 -1187181 -1749157 47.1333333 9.6333333 470800 93800 NT42 NL32-02 T MT LS 00 V MATLERKOPF Matler Kopf Matler Kopf 1993-12-22
+1 -1187162 -1749158 47.1333333 9.6166667 470800 93700 NT42 NL32-02 T PASS LS 00 LS N MATTAJOCH Mattajoch Mattajoch 1994-04-28
+1 -1187164 -1749160 47.2166667 9.5333333 471300 93200 NT42 NL32-02 P PPL LS 00 V MAUERN Mauern Mauern 1993-12-22
+1 -1187163 -1749161 47.2166667 9.5333333 471300 93200 NT42 NL32-02 A ADM1 LS 00 N MAUREN Mauren Mauren 1993-12-22
+1 -1187164 -1749162 47.2166667 9.5333333 471300 93200 NT42 NL32-02 P PPL LS 00 N MAUREN Mauren Mauren 1993-12-22
+1 -1187163 -1749163 47.2166667 9.5333333 471300 93200 NT42 NL32-02 A ADM1 LS 00 V MAURENSCHAANWALD Mauren-Schaanwald Mauren-Schaanwald 1993-12-22
+1 -1187165 -1749164 47.2333333 9.5333333 471400 93200 NT43 NL32-02 P PPLX LS 00 N MITTLERERSCHELLENBERG Mittlerer Schellenberg Mittlerer Schellenberg 1993-12-22
+1 419574 535545 47.1500000 9.5000000 470900 93000 NT32 NL32-02 P PPL LS 00 V MOLIHOLZ Möliholz Moliholz 1999-01-26
+1 419574 535574 47.1500000 9.5000000 470900 93000 NT32 NL32-02 P PPL LS 00 N MUHLEHOLZ Mühleholz Muhleholz 1999-01-26
+1 -1187166 -1749165 47.0500000 9.6000000 470300 93600 NT41 NL32-02 T MT LS 00 N NAAFKOPF Naafkopf Naafkopf 1993-12-22
+1 -1187166 -1749166 47.0500000 9.6000000 470300 93600 NT41 NL32-02 T MT LS 00 V NAUFKOPF Nauf Kopf Nauf Kopf 1993-12-22
+1 -1187167 -1749167 47.2000000 9.5500000 471200 93300 NT42 NL32-02 P PPL LS 00 N NENDELN Nendeln Nendeln 1993-12-22
+1 -1187168 -1749168 47.1166667 9.6333333 470700 93800 NT41 NL32-02 T MT LS 00 V OCHSENBERG Ochsenberg Ochsenberg 1993-12-22
+1 -1187168 -1749169 47.1166667 9.6333333 470700 93800 NT41 NL32-02 T MT LS 00 N OCHSENKOPF Ochsenkopf Ochsenkopf 1993-12-22
+1 -1187169 -1749170 47.1833333 9.5333333 471100 93200 NT42 NL32-02 A ADM1 LS 00 N PLANKEN Planken Planken 1993-12-22
+1 -1187170 -1749171 47.1833333 9.5333333 471100 93200 NT42 NL32-02 P PPL LS 00 N PLANKEN Planken Planken 1993-12-22
+1 -1187171 -1749172 47.0500000 9.7500000 470300 94500 NT51 NL32-02 T MTS LS 00 V RATIKON Rätikon Ratikon 1993-12-22
+1 -1187171 -1749174 47.0500000 9.7500000 470300 94500 NT51 NL32-02 T MTS LS 00 V RHAETIKON Rhaetikon Rhaetikon 1993-12-22
+1 -1187171 -1749175 47.0500000 9.7500000 470300 94500 NT51 NL32-02 T MTS LS 00 N RHATIKON Rhätikon Rhatikon 1993-12-22
+1 -1187171 -1749176 47.0500000 9.7500000 470300 94500 NT51 NL32-02 T MTS LS 00 V RHATIKONMOUNTAINS Rhätikon Mountains Rhatikon Mountains 1993-12-22
+1 419569 535539 47.1166667 9.5500000 470700 93300 NT41 NL32-02 P PPL LS 00 V ROTABODA Rotaboda Rotaboda 1999-01-26
+1 419569 535573 47.1166667 9.5500000 470700 93300 NT41 NL32-02 P PPL LS 00 N ROTENBODEN Rotenboden Rotenboden 1999-01-26
+1 -1187174 -1749189 47.2333333 9.5166667 471400 93100 NT33 NL32-02 P PPL LS 00 V RUGELL Rugell Rugell 1993-12-22
+1 -1187173 -1749190 47.2333333 9.5166667 471400 93100 NT33 NL32-02 A ADM1 LS 00 N RUGGELL Ruggell Ruggell 1993-12-22
+1 -1187174 -1749191 47.2333333 9.5166667 471400 93100 NT33 NL32-02 P PPL LS 00 N RUGGELL Ruggell Ruggell 1993-12-22
+1 -1187175 -1749192 47.2333333 9.6333333 471400 93800 NT43 NL32-02 H STM LS 00 N SAMINA Samina Samina 1993-12-22
+1 -1187176 -1749193 47.1666667 9.5833333 471000 93500 NT42 NL32-02 T VAL LS 00 N SAMINATAL Saminatal Saminatal 1993-12-22
+1 -1187176 -1749194 47.1666667 9.5833333 471000 93500 NT42 NL32-02 T VAL LS 00 V SAMINATHAL Samina Thal Samina Thal 1993-12-22
+1 -1187177 -1749195 47.1000000 9.6333333 470600 93800 NT41 NL32-02 T PASS LS 00 N SAREISERJOCH Sareiser Joch Sareiser Joch 1993-12-22
+1 -1187178 -1749196 47.1666667 9.5000000 471000 93000 NT32 NL32-02 A ADM1 LS 00 N SCHAAN Schaan Schaan 1993-12-22
+1 -1187179 -1749197 47.1666667 9.5000000 471000 93000 NT32 NL32-02 P PPL LS 00 N SCHAAN Schaan Schaan 1993-12-22
+1 -1187180 -1749198 47.2166667 9.5666667 471300 93400 NT42 NL32-02 P PPL LS 00 N SCHAANWALD Schaanwald Schaanwald 1993-12-22
+1 -1187179 -1749199 47.1666667 9.5000000 471000 93000 NT32 NL32-02 P PPL LS 00 V SCHAN Schan Schan 1993-12-22
+1 -1187181 -1749200 47.1333333 9.6333333 470800 93800 NT42 NL32-02 T MT LS 00 N SCHEIENKOPF Scheienkopf Scheienkopf 1993-12-22
+1 -1187182 -1749201 47.2333333 9.5333333 471400 93200 NT43 NL32-02 A ADM1 LS 00 N SCHELLENBERG Schellenberg Schellenberg 1993-12-22
+1 -1187183 -1749202 47.2333333 9.5333333 471400 93200 NT43 NL32-02 P PPL LS 00 N SCHELLENBERG Schellenberg Schellenberg 1993-12-22
+1 -1187181 -1749203 47.1333333 9.6333333 470800 93800 NT42 NL32-02 T MT LS 00 V SCHEUENKOPF Scheuenkopf Scheuenkopf 1993-12-22
+1 419570 535541 47.1333333 9.5500000 470800 93300 NT42 NL32-02 P PPL LS 00 N SILUM Silum Silum 1999-01-26
+1 419568 535538 47.1166667 9.5666667 470700 93400 NT41 NL32-02 P PPL LS 00 N SUCKA Sücka Sucka 1999-01-26
+1 -1187184 -1749204 47.1000000 9.5333333 470600 93200 NT41 NL32-02 A ADM1 LS 00 N TRIESEN Triesen Triesen 1993-12-22
+1 -1187185 -1749205 47.1000000 9.5333333 470600 93200 NT41 NL32-02 P PPL LS 00 N TRIESEN Triesen Triesen 1993-12-22
+1 -1187186 -1749206 47.1166667 9.5333333 470700 93200 NT41 NL32-02 A ADM1 LS 00 N TRIESENBERG Triesenberg Triesenberg 1993-12-22
+1 -1187187 -1749207 47.1166667 9.5333333 470700 93200 NT41 NL32-02 P PPL LS 00 N TRIESENBERG Triesenberg Triesenberg 1993-12-22
+1 -1187188 -1749208 47.2500000 9.5333333 471500 93200 NT43 NL32-02 H MRSH LS 00 N UNTERESRIET Unteres Riet Unteres Riet 1993-12-22
+1 -1187189 -1749209 47.1333333 9.5166667 470800 93100 NT32 NL32-02 A ADM1 LS 00 N VADUZ Vaduz Vaduz 1993-12-22
+1 -1187190 -1749210 47.1333333 9.5166667 470800 93100 NT32 NL32-02 P PPLC LS 00 N VADUZ Vaduz Vaduz 1995-04-26
+1 419571 535542 47.0833333 9.5833333 470500 93500 NT41 NL32-02 T VAL LS 00 N VALUNA Valüna Valuna 1999-01-26
+1 -1187191 -1749211 47.2333333 9.5333333 471400 93200 NT43 NL32-02 P PPLX LS 00 N VORDERERSCHELLENBERG Vorderer Schellenberg Vorderer Schellenberg 1993-12-22
+1 -1187192 -1749212 47.0500000 9.5833333 470300 93500 NT41 NL32-02 T PK LS 00 N VORDERGRAUSPITZ Vorder-Grauspitz Vorder-Grauspitz 1993-12-22
+1 419567 535537 47.1000000 9.5333333 470600 93200 NT41 NL32-02 P PPL LS 00 V WANGERBARG Wangerbärg Wangerbarg 1999-01-26
+1 419567 535572 47.1000000 9.5333333 470600 93200 NT41 NL32-02 P PPL LS 00 N WANGERBERG Wangerberg Wangerberg 1999-01-26
Added: packages/thuban/branches/upstream/current/Extensions/gns2shp/test/test_gns2shp.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/gns2shp/test/test_gns2shp.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/gns2shp/test/test_gns2shp.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,90 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test gns2shp extension.
+"""
+
+__version__ = "$Revision: 2484 $"
+# $Source$
+# $Id: test_gns2shp.py 2484 2004-12-18 22:40:45Z jan $
+
+import unittest
+import os
+import sys
+
+# If run directly as a script, add Thuban's test directory, the Lib
+# directory and the Thuban directory itself to the path.
+# Otherwise we assume that the importing code as already done it
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ "..", "..", "..", "test"))
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ "..", "..", "..", "Lib"))
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ "..", "..", ".."))
+
+import support
+import shapelib
+from dbflib import DBFFile, FTString, FTInteger, FTDouble
+from Extensions.gns2shp.gns2shp import gns2shp
+
+class gns2shpTest(unittest.TestCase, support.FileTestMixin):
+
+ def test(self):
+ """Test for correct creation of Shapefile from GNS text file format"""
+ eq = self.assertEquals
+
+ # create a temporary gns file (use liechtenstein as reference)
+ filename = self.temp_file_name('test.gns')
+ os.system('cp ls.txt %s' % filename)
+
+ # convert the reference gns file to shapefile
+ dest_filename = self.temp_file_name('test')
+ n = gns2shp(filename, dest_filename)
+
+ # is the number of shapes correct?
+ eq(n, 88) # what gns2shp reports
+ # and now the actually written ones
+ shp = shapelib.ShapeFile(dest_filename)
+ numshapes, shapetype, mins, maxs = shp.info()
+ eq(numshapes, n)
+
+ # correct shapefile type?
+ eq(shapetype, shapelib.SHPT_POINT)
+
+ # attribute data correct?
+ field_types = { 'RC': FTInteger,
+ 'UFI': FTInteger,
+ 'UNI': FTInteger,
+ 'UTM': FTString,
+ 'JOG': FTString,
+ 'FC': FTString,
+ 'DSG': FTString,
+ 'PC': FTInteger,
+ 'CC1': FTString,
+ 'ADM1': FTString,
+ 'ADM2': FTString,
+ 'DIM': FTInteger,
+ 'CC2': FTString,
+ 'NT': FTString,
+ 'LC': FTString,
+ 'SHORT_FORM': FTString,
+ 'GENERIC': FTString,
+ 'SORT_NAME': FTString,
+ 'FULL_NAME': FTString,
+ 'FULL_ND': FTString,
+ 'MODIFY_DAT': FTString}
+ dbf = DBFFile(dest_filename)
+ eq(dbf.record_count(), n) # correct number of data sets?
+ eq(dbf.field_count(), len(field_types)) # correct number of fields?
+ for i in range(dbf.field_count()):
+ ftype, name, width, prec = dbf.field_info(i)
+ eq(ftype, field_types[name]) # field of correct type?
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,21 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# import the actual module
+import importAPR
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'importAPR',
+ version = '0.1.1',
+ authors= [ 'Jan-Oliver Wagner' ],
+ copyright = '2003, 2004 Intevation GmbH',
+ desc = _("Import a ArcView project file (.apr)\n" \
+ "and convert it to Thuban.")))
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/apr.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/apr.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/apr.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,225 @@
+# Copyright (C) 2003-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes for ArcView Objects as in '.apr'-files.
+
+The classes are only added to this module if they
+are considered to be complete and whenever possible
+accompanied by unit tests (see tests/).
+Experimental classes should remain in importAPR.py.
+"""
+
+__version__ = "$Revision: 2629 $"
+
+from math import ceil
+
+from Thuban.Model.color import Color, Transparent, Black
+from Thuban.Model.range import Range
+from Thuban.Model.classification import ClassGroupProperties
+
+from odb import ODBBaseObject
+
+class APR_BLnSym(ODBBaseObject):
+ """Line symbol object.
+ Always references a color object TClr via 'Color'.
+
+ The stroke width 'Width' is always given, but the scale is
+ unclear so far (e.g. which width is actually meant with value '0.1'?).
+ Meanwhile, the ceiling of 'Width' is applied to be stroke width
+ in pixels.
+
+ Finally, there seems always to be a 'Pattern'-List consisting of
+ float values. No idea so far, how to interpret this (Thuban does
+ not support pattern yet anyway).
+ """
+ _obj_refs = [ 'Color' ]
+ _values = [ 'Width', 'Pattern' ]
+
+ def GetThubanProp(self):
+ """Create a Thuban ClassGroupProperty from this object and
+ return it.
+ """
+ prop = ClassGroupProperties()
+ prop.SetLineColor(self.Get('Color').GetThubanColor())
+ prop.SetLineWidth(int(ceil(float(self.Get('Width')))))
+ return prop
+
+class APR_BMkSym(ODBBaseObject):
+ """Point symbol object.
+ Always references a Color and a Background Color via 'Color', 'BgColor'.
+ For Thuban, Color is interpreted as line color and BGColor is
+ interpreted as fill color.
+
+ Next, there is always a 'Font' reference. Probably this defines
+ the font for the label. This is not interpreted for Thuban.
+
+ There is always a Size element. It is not clear how 'size'
+ defined in ArcView.
+
+ There is always a Angle element, but I don't know how this is
+ defined. I only sighted the value of 360 so far.
+
+
+ Finally, there seems always to be a 'Pattern'-List consisting of
+ float values. No idea so far, how to interpret this (Thuban does
+ not support pattern yet anyway).
+ """
+
+ _obj_refs = [ 'Color', 'BgColor', 'Font' ]
+ _values = [ 'Angle', 'Size', 'Pattern' ]
+
+ def GetThubanProp(self):
+ """Create a Thuban ClassGroupProperty from this object and
+ return it.
+
+ In Thuban, the points have all the same size,
+ but we can vary the width of the line.
+ """
+ prop = ClassGroupProperties()
+ prop.SetSize(int(ceil(float(self.Get('Size')))))
+ prop.SetLineColor(self.Get('Color').GetThubanColor())
+ prop.SetFill(self.Get('BgColor').GetThubanColor())
+ return prop
+
+class APR_BShSym(ODBBaseObject):
+ """Polygon symbol object, either filled with a single color or
+ with a pattern.
+ .
+ Always references TClr objects via 'Color', 'OutlineColor' and 'BgColor'.
+ Always has attributes 'OutlineWidth' and 'Outline'.
+
+ OutlineColor is interpreted to be the Thuban line color, OutlineWidth
+ as the Thuban line width.
+ 'Color' is interpreted to be the Thuban fill color.
+ 'BgColor' is not interpreted and probably has something to do with
+ patterns (Stripple).
+ 'Stripple' ist not interpreted in Thuban. It is a pattern definition
+ based on a bitpattern. Thuban has no Patterns yet.
+
+ It is unclear what 'Outline' defines and thus is not used for Tuban.
+ """
+ _obj_refs = [ 'Color', 'OutlineColor', 'BgColor', 'Stripple' ]
+ _values = [ 'OutlineWidth', 'Outline' ]
+
+ def GetThubanProp(self):
+ """Create a Thuban ClassGroupProperty from this object and
+ return it.
+ """
+ prop = ClassGroupProperties()
+ prop.SetLineWidth(int(ceil(float(self.Get('OutlineWidth')))))
+ prop.SetLineColor(self.Get('OutlineColor').GetThubanColor())
+ prop.SetFill(self.Get('Color').GetThubanColor())
+ return prop
+
+class APR_LClass(ODBBaseObject):
+ """This object describes the range and label of a class
+ within a legend.
+
+ 'IsText' determines whether 'MinStr'/'MaxStr' are given, else
+ 'MinNum'/'MaxNum' should be there.
+ So far, only String-Ranges with identical 'MinStr'/'MaxStr' have
+ been sighted.
+
+ 'MinNum' may not be there. In this case assume it to be -oo.
+
+ There are objects with 'IsNoData' set to 1. Not yet sure how to
+ treat them.
+
+ However, objects have been sighted that only have 'IsText' and
+ 'Precision': We assume an empty label and a full range.
+
+ No referenced objects.
+ """
+ _obj_refs = [ ]
+ _values = [ 'IsText', 'MinStr', 'MaxStr', 'MinNum', 'MaxNum', 'Label',
+ 'Precision', 'IsNoData' ]
+
+ def GetThubanRange(self):
+ """Return a Thuban range that corresponds to this object.
+
+ The returned object is a
+ - Range-Object in case of a numerical range.
+ - String-Object in case of a text range (assuming that
+ text objects occur only with 'MinStr' == 'MaxStr'.
+ """
+ if hasattr(self, 'IsText'):
+ if hasattr(self, 'MinStr'):
+ return self.MinStr
+ else:
+ return ''
+
+ # build range
+ if hasattr(self, 'MinNum'):
+ range_str = ']' + self.MinNum + ';'
+ else:
+ range_str = ']-oo;'
+ if hasattr(self, 'MaxNum'):
+ range_str = range_str + self.MaxNum + ']'
+ else:
+ range_str = None
+
+ if hasattr(self, 'MinNum') and hasattr(self, 'MaxNum'):
+ if self.MinNum == self.MaxNum:
+ range_str = '[' + self.MinNum + ';' + self.MaxNum + ']'
+ return Range(range_str)
+
+ def GetLabel(self):
+ """Return the label string.
+ Return an empty string if there is no 'Label'.
+ """
+ if hasattr(self, 'Label'):
+ return self.Label
+ else:
+ return ''
+
+
+class APR_TClr(ODBBaseObject):
+ """Color object. Appears in 3 styles:
+ 1. no attributes: (so far assumed as black)
+ 2. only 'Name': a string that describes the color.
+ Seen only "Transparent".
+ 3. 'Red', 'Green', 'Blue': RGB code. Each value in '0xffff' style.
+ 3.1 Only one or two of the colors are defined. It is assumed
+ that in this case the rest is equal to 0x0000
+ 3.2 Some hex-codes are incomplete (eg. 0xff). It is assumed
+ that the missing digits are "0".
+
+ No referenced objects.
+ """
+ _obj_refs = [ ]
+ _values = [ 'Name', 'Red', 'Green', 'Blue' ]
+
+ def GetThubanColor(self):
+ """Return a Thuban Color object; returns None if a problem
+ occured.
+ """
+ if hasattr(self, 'Red') or hasattr(self, 'Green') or \
+ hasattr(self, 'Blue'):
+ rgb = { 'Red': 0, 'Green': 0, 'Blue': 0 } # default for missing
+ # parts: 0x0000
+
+ for color in [ 'Red', 'Green', 'Blue' ]:
+ if hasattr(self, color):
+ s = getattr(self, color)
+ # It seems that ArcView sometimes uses only
+ # 2 bytes for a color definition, eg. 0xff.
+ # It is assumed that this is the same as
+ # 0x00ff (and not the same as 0xff00). At
+ # least color comparison shows this.
+ # Thus we do not need to append "00" if length
+ # of s is < 6. The following conversion does is
+ # right even for the short strings.
+ rgb[color] = int(s, 16)/float(int('0xffff', 16))
+ return Color(rgb['Red'], rgb['Green'], rgb['Blue'])
+ elif hasattr(self, 'Name'):
+ if self.Name == 'Transparent':
+ return Transparent
+ else:
+ return None
+ else:
+ return Black
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/importAPR.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/importAPR.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/importAPR.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,338 @@
+# Copyright (C) 2003-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Import a ArcView project file (.apr) and convert it
+to Thuban.
+"""
+
+__version__ = "$Revision: 2721 $"
+# $Source$
+# $Id: importAPR.py 2721 2007-01-13 15:11:42Z dpinte $
+
+import os, sys
+
+from types import StringType
+
+import wx
+
+from Thuban.Model.extension import Extension
+from Thuban.Model.base import TitledObject, Modifiable
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu
+from Thuban import _
+from Thuban.Model.layer import Layer
+from Thuban.Model.classification import ClassGroupRange, ClassGroupSingleton
+
+from odb import ODBBaseObject
+from apr import APR_LClass, APR_TClr, APR_BLnSym, APR_BMkSym, APR_BShSym
+
+class ODBExtension(Extension):
+ def TreeInfo(self):
+ return (_("Extension: %s") % self.title,
+ [ object.TreeInfo() for object in self.objects ])
+
+class APR_FTheme(ODBBaseObject):
+ _obj_refs = [ 'Source', 'Legend' ]
+
+class APR_Legend(ODBBaseObject):
+ """Legend object.
+ There could one or more Class objects. Each class corresponds to a
+ Child in the Symbols.
+ """
+ _obj_refs = [ 'FieldNames', 'Symbols', 'Class', 'NullSym',
+ 'NullValues', 'StatValues' ]
+
+class APR_VShSym(ODBBaseObject):
+ """Pattern Object(Symbol).
+ """
+ _obj_refs = [ 'Color', 'OutlineColor', 'BgColor' ]
+ _values = [ 'Outline', 'Outlinewidth', 'Angle', 'YSeparation',
+ 'PenSize' ]
+
+class APR_Project(ODBBaseObject):
+ _obj_refs = [ 'Doc' ]
+
+class APR_ShpSrc(ODBBaseObject):
+ _obj_refs = [ 'Name' ]
+
+class APR_SrcName(ODBBaseObject):
+ _obj_refs = [ 'FileName' ]
+
+class APR_SymList(ODBBaseObject):
+ _obj_refs = [ 'Child' ]
+
+class APR_View(ODBBaseObject):
+ _obj_refs = [ 'Theme', 'ITheme' ]
+
+class ODB(TitledObject, Modifiable):
+
+ def __init__(self):
+ TitledObject.__init__(self, 'ODB Object')
+ self._objects = {}
+ self._version = None
+ self._filename = None
+ self.name = None # required for Thuban.model.extension.Extension
+
+ def SetFileName(self, fname):
+ self._filename = fname
+ self.name = fname
+
+ def AddObject(self, object):
+ self._objects[object.number] = object
+
+ def GetObjects(self):
+ return self._objects
+
+ def GetProject(self):
+ """Return the main Root if it is a Project, else None."""
+ # it is assumed that the first object is the ODB object
+ if self._objects[1].type != 'ODB':
+ return None
+ if self._objects[1].FirstRootClassName != 'Project':
+ return None
+
+ # it is assumed that the second object is the first root
+ o = self._objects[2]
+ if o.type != 'Project':
+ return None
+ return o
+
+ def TreeInfo(self):
+ items = []
+ items.append(_('Format version: %s') % self._version)
+ p = self.GetProject()
+ items.append(_('Project Name: %s') % p.Name)
+ for doc in p.Get('Doc'):
+ items.append(doc.TreeInfo())
+ return [_("ODB File '%s'" % self._filename), items]
+
+def parse_apr(fname):
+ """Load a ArcView project file.
+
+ fname -- Filename of the .apr file
+
+ Return: the ODB class object.
+ """
+ odb = ODB()
+ odb.SetFileName(fname)
+
+ apr = open(fname, 'r').readlines()
+
+ # get the version from the first line (eg. from "/3.1")
+ odb._version = apr.pop(0)[1:]
+
+ i = 0
+ in_object = False
+ for line in apr:
+ i += 1
+ if line[0] == '(':
+ line = line[1:]
+ type, number = line.split('.')
+ number = int(number)
+ class_name = 'APR_' + type
+ try:
+ clazz = eval(class_name)
+ object = clazz(odb, type, number)
+ except:
+ object = ODBBaseObject(odb, type, number)
+ in_object = True
+ continue
+ if line[0] == ')':
+ in_object = False
+ odb.AddObject(object)
+ if in_object:
+ line = line.strip()
+ if len(line) == 0: continue
+ try:
+ property, value = line.split(':', 1)
+ property = property.strip()
+ value = value.strip()
+ except:
+ print "Error in line %d:" % i, line
+ continue
+ if value[0] == '"':
+ value = value[1:-1]
+ setattr(object, property, value)
+ return odb
+
+def import_apr_dialog(context):
+ """Request filename from user and run importing of apr file.
+
+ context -- The Thuban context.
+ """
+ dlg = wx.FileDialog(context.mainwindow,
+ _("Select APR file"), ".", "",
+ _("ArcView Project Files (*.apr)|*.apr|") +
+ _("All Files (*.*)|*.*"),
+ wx.OPEN|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ dlg.Destroy()
+ else:
+ return
+
+ odb = parse_apr(filename)
+ if odb is None:
+ context.mainwindow.RunMessageBox(_("Import APR"), _("Loading failed"))
+ return
+ else:
+ context.mainwindow.RunMessageBox(_("Import APR"),
+ _("%d objects loaded" %
+ len(odb.GetObjects().keys())))
+
+ # find the views of the APR file
+ views = {}
+ p = odb.GetProject()
+ for doc in p.Get('Doc'):
+ if doc.type != 'View':
+ continue
+ views[doc.Name] = doc
+
+ # it is possible that a APR file has no view at all
+ if len(views) == 0:
+ context.mainwindow.RunMessageBox(_("Import APR"),
+ _("No view found in APR file"))
+ return
+
+ # let the user select one of the views
+ if len(views) > 1:
+ titles = views.keys()
+ dlg = wx.SingleChoiceDialog(context.mainwindow,
+ _('Pick a View to import:'),
+ _('Import APR'), titles,
+ style = wx.DEFAULT_DIALOG_STYLE |
+ wx.RESIZE_BORDER)
+ if dlg.ShowModal() == wx.ID_OK:
+ view = views[views.keys()[dlg.GetSelection()]]
+ else:
+ return
+ else:
+ view = views[views.keys()[0]]
+
+ # load the themes of the View as layers into Thuban
+ count_theme = 0
+ count_theme_fail = 0
+ for theme in view.Get('Theme'):
+ if theme.type != 'FTheme':
+ continue
+ count_theme += 1
+ filename = theme.Get('Source').Get('Name').Get('FileName').Path
+ try:
+ store = context.application.Session().OpenShapefile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(_('Add Layer'),
+ _("Can't open the file '%s'.") % filename)
+ count_theme_fail += 1
+ else:
+ title = theme.Name
+ apr_legend = theme.Get('Legend')
+
+ map = context.mainwindow.canvas.Map()
+
+ # create layer
+ layer = Layer(title, store)
+
+ # set the field for classification (if there is one in the apr)
+ if hasattr(apr_legend, 'FieldNames'):
+ apr_fieldname = apr_legend.Get('FieldNames').S
+ # unfortunately, the APR file does not store the actual
+ # Name of the column, but always makes the first character
+ # a capital letter, the rest lower case.
+ # Therefore, we have to search through the table of the
+ # layer to find out the correct spelling.
+ table_columns = layer.ShapeStore().Table().Columns()
+ for column in table_columns:
+ if apr_fieldname.lower() == column.name.lower():
+ layer.SetClassificationColumn(column.name)
+ break
+
+ clazz = layer.GetClassification()
+ apr_classes = apr_legend.Get('Class')
+ if not isinstance(apr_classes, list):
+ apr_classes = [ apr_classes ]
+ apr_symbols = apr_legend.Get('Symbols').Get('Child')
+ if not isinstance(apr_symbols, list):
+ apr_symbols = [ apr_symbols ]
+ i = -1
+ for symbol in apr_symbols:
+ i += 1
+
+ if hasattr(apr_classes[i], 'IsNoData'):
+ group = clazz.GetDefaultGroup()
+ group.SetLabel(apr_classes[i].Label)
+ continue
+
+ # create a new group property from the symbol
+ prop = symbol.GetThubanProp()
+
+ # build range
+ range = apr_classes[i].GetThubanRange()
+
+ if isinstance(range, StringType):
+ new_group = ClassGroupSingleton(value = range,
+ props = prop,
+ label = apr_classes[i].GetLabel())
+ else:
+ new_group = ClassGroupRange(_range = range,
+ props = prop,
+ label = apr_classes[i].GetLabel())
+ clazz.AppendGroup(new_group)
+
+ map.AddLayer(layer)
+
+ map.SetTitle(view.Name)
+
+ # fit the new map to the window
+ context.mainwindow.canvas.FitMapToWindow()
+
+ context.mainwindow.RunMessageBox(_('Import APR'),
+ _('Imported %d out of %d themes of view "%s" ...') % \
+ (count_theme - count_theme_fail, count_theme, view.Name))
+
+ # import_apr as an extension to Thuban
+ if context.session.HasExtensions():
+ for ext in context.session.Extensions():
+ if ext.Title() == apr_import_extension.Title():
+ ext.AddObject(odb)
+ return
+
+ # no extension found, so lets make a new
+ context.session.AddExtension(apr_import_extension)
+ apr_import_extension.AddObject(odb)
+
+if __name__ == "__main__": # import_apr executed as a command line tool
+ if len(sys.argv) == 2:
+ odb = parse_apr(sys.argv[1])
+ print "%d objects loaded" % len(odb.GetObjects().keys())
+
+ def print_structured_list(lst, indent = ''):
+ for item in lst:
+ if isinstance(item, StringType):
+ print indent + item
+ elif isinstance(item, list):
+ print_structured_list(item, indent + ' ')
+
+ print_structured_list(odb.TreeInfo())
+ sys.exit(0)
+ else:
+ print 'usage: %s apr-file' % sys.argv[0]
+ sys.exit(1)
+
+apr_import_extension = ODBExtension('APR Import')
+
+# register the new command
+registry.Add(Command('import-apr', _('Import apr-file...'), import_apr_dialog,
+ helptext = _('Import a ArcView project file')))
+
+# find the experimental menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu('experimental',
+ _('Experimenta&l'))
+
+# finally add the new entry to the experimental menu
+experimental_menu.InsertItem('import-apr')
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/odb.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/odb.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/odb.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,131 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes for generic ArcView ODB Objects
+as in '.apr', '.avl' and other files.
+"""
+
+__version__ = "$Revision: 1882 $"
+
+from types import StringType
+
+from Thuban import _
+
+class ODBBaseObject:
+
+ """Base class for ODB objects."""
+
+ _obj_refs = [] # override this list with the object names
+ # as strings that are referenced.
+ _values = [] # override this list with the keywords
+ # for known values of the class.
+
+ def __init__(self, parent_odb, type, number):
+ self._parent_odb = parent_odb
+ self.type = type
+ self.number = number
+
+ def __setattr__(self, attr, value):
+ """If an attribute is set that already exists,
+ a list is created to contain both. Any further
+ attribute with the same name is appended to the list.
+ """
+ if hasattr(self, attr):
+ v = getattr(self, attr)
+ if isinstance(v, list):
+ v.append(value)
+ else:
+ self.__dict__[attr] = [v, value]
+ else:
+ self.__dict__[attr] = value
+
+ def __repr__(self):
+ """The string represenation of an object is the syntax
+ as used in the ODB file.
+ """
+ s = '(' + self.type + '.' + str(self.number) + '\n'
+ for k in self.__dict__.keys():
+ if k in [ '_parent_odb', 'type', 'number']: continue
+ v = self.__dict__[k]
+ if isinstance(v, list):
+ for val in v:
+ s += "\t%s:\t%s\n" % (k, val)
+ else:
+ s += "\t%s:\t%s\n" % (k, v)
+ s += ')\n'
+ return s
+
+ def Get(self, attr):
+ """If an attribute is a pointer (or a list of pointers)
+ to another object (other objects), references are resolved
+ to point to the corresponding objects.
+
+ attr -- string with the name of the attribute
+ """
+ if not hasattr(self, attr):
+ print "Object %s.%s has no attribute %s!" % ( self.type,
+ self.number, attr)
+ return None
+
+ if attr in self._obj_refs:
+ if isinstance(self.__dict__[attr], list):
+ lst = []
+ for obj_id in self.__dict__[attr]:
+ obj_id = int(obj_id)
+ if not self._parent_odb.GetObjects().has_key(obj_id):
+ print "Object #%d missing!" % obj_id
+ else:
+ lst.append(self._parent_odb.GetObjects()[obj_id])
+ return lst
+ else:
+ obj_id = int(self.__dict__[attr])
+ if not self._parent_odb.GetObjects().has_key(obj_id):
+ print "Object #%d missing!" % s
+ return None
+ return self._parent_odb.GetObjects()[obj_id]
+
+ return self.__dict__[attr]
+
+ def TreeInfo(self):
+ """Return the information in a tree-like structure."""
+ items = []
+
+ # known values
+ for o in self._values:
+ if hasattr(self, o):
+ items.append('%s: %s' % (o, self.Get(o)))
+
+ # the objects
+ for o in self._obj_refs:
+ if not hasattr(self, o): continue
+ if not isinstance(self.Get(o), list):
+ items.append(self.Get(o).TreeInfo())
+ # add the variable name of the object:
+ items[-1][0] = '%s: %s' % (o, items[-1][0])
+ continue
+ for obj in self.Get(o):
+ items.append(obj.TreeInfo())
+ # add the variable name of the object:
+ items[-1][0] = '%s: %s' % (o, items[-1][0])
+
+ # unknown values
+ for k in self.__dict__.keys():
+ if k in [ '_parent_odb', 'type', 'number']: continue
+ if k in self._obj_refs: continue
+ if k in self._values: continue
+ v = self.__dict__[k]
+ if isinstance(v, list):
+ items.append(_("Unknown Object list named: '%s'") % k)
+ else:
+ if isinstance(v, StringType):
+ items.append(_("Unknown Value named: '%s' with value '%s'")\
+ % ( k, v ))
+ else:
+ items.append(_('Unknown Object named: %s') % k)
+
+ return [self.type, items]
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/samples/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/samples/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/samples/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,5 @@
+Howto view the sample apr-files:
+
+iceland.apr: start Thuban from the main CVS thuban directory.
+ (the paths to the Iceland datafiles are relative
+ and will work then)
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/samples/iceland.apr
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/samples/iceland.apr 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/samples/iceland.apr 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,4307 @@
+/3.1
+(ODB.1
+ FirstRootClassName: "Project"
+ Roots: 2
+ Version: 32
+)
+
+(Project.2
+ Name: "iceland.apr"
+ CreationDate: "Montag, 15. September 2003 10:16:20"
+ GUIName: "Project"
+ Win: 3
+ CSMgr: 4
+ DocExts: 5
+ VisGUIWidth: 90
+ Doc: 6
+ Doc: 195
+ Buttons: 611
+ Buttons: 612
+ Buttons: 613
+ Scripts: 614
+ Prefs: 615
+ WorkDir: 1461
+ WinX: -4
+ WinY: -3
+ WinW: 1032
+ WinH: 747
+ SerialNumber: "42"
+ SelColor: 1462
+ GUINames: 1463
+ GUINames: 1464
+ GUINames: 1465
+ GUINames: 1466
+ GUINames: 1467
+ GUINames: 1468
+ GUINames: 1469
+ TocWidthScale: 1.00000000000000
+)
+
+(DocWin.3
+ Owner: 2
+ Open: 1
+ X: -4
+ Y: -4
+ W: 1034
+ H: 643
+)
+
+(CSMgr.4
+)
+
+(DocAct.5
+ Doc: 2
+)
+
+(View.6
+ Name: "Political Map of Iceland with Cultural Landmarks and Roads"
+ Creator: "Test A. Little"
+ CreationDate: "Montag, 15. September 2003 10:16:31"
+ GUIName: "View"
+ Win: 7
+ CSMgr: 8
+ DocExts: 10
+ DocExts: 11
+ Graphics: 12
+ Theme: 19
+ Theme: 68
+ Theme: 154
+ LastScale: 4619242.64638806320000
+ Dpy: 13
+ TOCWidth: 150
+ CoordPrecision: 2
+)
+
+(DocWin.7
+ Owner: 6
+ X: -4
+ Y: -4
+ W: 1034
+ H: 643
+)
+
+(CSMgr.8
+ Client: 9
+)
+
+(CSClient.9
+ Client: 10
+ ReqName: "ClientNfy"
+)
+
+(PanMgr.10
+ Doc: 6
+)
+
+(DocAct.11
+ Doc: 6
+)
+
+(GList.12
+ Dpy: 13
+ FormatNumb: 18
+)
+
+(MapDpy.13
+ Left: -22.93289795163312
+ Bottom: 63.31776466852502
+ Top: 66.57350349909144
+ Right: -13.38145151379742
+ ReportUnits: 4
+ Units: 10
+ Scale: 14
+ FrameTop: 6.37500000000000
+ FrameRight: 9.05208333333333
+ PageDpy: 15
+ FitToPage: 1
+ MouseLoc: 17
+)
+
+(Numb.14
+ N: 0.94771858819998
+)
+
+(PageDpy.15
+ Top: 6.37500000000000
+ Right: 9.05208333333333
+ ReportUnits: 1
+ Units: 1
+ Scale: 16
+ ZoomRight: 9.05208333333333
+ ZoomTop: 6.37500000000000
+ GridSpacingX: 0.25000000000000
+ GridSpacingY: 0.25000000000000
+)
+
+(Numb.16
+ N: 0.11047180667434
+)
+
+(PointD.17
+ x: -13.40343412930452
+ y: 68.25401771762704
+)
+
+(Numb.18
+)
+
+(FTheme.19
+ Name: "Roads"
+ Source: 20
+ Flags: 0x06
+ Legend: 37
+ Threshold: 56
+ View: 6
+ GSet: 57
+ LegEditScript: "View.EditLegend"
+ TxPos: 58
+ AttrRules: 59
+ AttrRules: 60
+ AttrRules: 61
+ AttrRules: 62
+ AttrRules: 63
+ AttrRules: 64
+ AttrRules: 65
+ AttrRules: 66
+ AttrRules: 67
+ SnapTolCursor: 1
+)
+
+(ShpSrc.20
+ Name: 21
+ FTab: 23
+)
+
+(SrcName.21
+ FileName: 22
+ Name: "roads-line.shp"
+ SubName: "Arc"
+ OwnerClass: "ShpSrc"
+)
+
+(FN.22
+ Path: "Data/iceland/roads-line.shp"
+)
+
+(FTab.23
+ Name: "roads-line.dbf"
+ BTab: 24
+ Fields: 35
+ Fields: 25
+ Fields: 26
+ Fields: 27
+ Fields: 28
+ Fields: 29
+ Fields: 30
+ Fields: 31
+ Fields: 32
+ Fields: 33
+ SelBits: 36
+ FSrc: 20
+)
+
+(dBASE.24
+ Name: "roads-line.dbf"
+ Fields: 25
+ Fields: 26
+ Fields: 27
+ Fields: 28
+ Fields: 29
+ Fields: 30
+ Fields: 31
+ Fields: 32
+ Fields: 33
+ FileName: 34
+)
+
+(Field.25
+ Name: "Fnode_"
+ Btab: 24
+ Alias: "Fnode_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.26
+ Name: "Tnode_"
+ Btab: 24
+ Alias: "Tnode_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.27
+ Name: "Lpoly_"
+ Btab: 24
+ Alias: "Lpoly_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.28
+ Name: "Rpoly_"
+ Btab: 24
+ Alias: "Rpoly_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.29
+ Name: "Length"
+ Btab: 24
+ Alias: "Length"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.30
+ Name: "Rdline_"
+ Btab: 24
+ Alias: "Rdline_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.31
+ Name: "Rdline_id"
+ Btab: 24
+ Alias: "Rdline_id"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.32
+ Name: "Rdlntype"
+ Btab: 24
+ Alias: "Rdlntype"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.33
+ Name: "Rdlnstat"
+ Btab: 24
+ Alias: "Rdlnstat"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(FN.34
+ Path: "Data/iceland/roads-line.dbf"
+)
+
+(Field.35
+ Name: "Shape"
+ Alias: "Shape"
+ Visible: 1
+ Type: 18
+ Order: -1
+)
+
+(Bitmap.36
+ NumBits: 839
+
+)
+
+(Legend.37
+ SymType: 0x01
+ LegType: 0x02
+ ClassType: 0x03
+ FieldNames: 38
+ Symbols: 39
+ Class: 48
+ Class: 49
+ Class: 50
+ Class: 51
+ StdDevs: 1.00000000000000
+ NullSym: 52
+ NullValues: 54
+ StatValues: 55
+ Precision: -3
+)
+
+(AVStr.38
+ S: "Rdlntype"
+)
+
+(SymList.39
+ Child: 40
+ Child: 42
+ Child: 44
+ Child: 46
+)
+
+(BLnSym.40
+ Color: 41
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.41
+)
+
+(BLnSym.42
+ Color: 43
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.43
+ Red: 0xa5a5
+ Green: 0xa5a5
+ Blue: 0xa5a5
+)
+
+(BLnSym.44
+ Color: 45
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.45
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(BLnSym.46
+ Color: 47
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.47
+ Name: "Transparent"
+)
+
+(LClass.48
+ Label: "1"
+ MinNum: 2.00000000000000
+ MaxNum: 2.00000000000000
+ Precision: -3
+)
+
+(LClass.49
+ Label: "2"
+ MinNum: 3.00000000000000
+ MaxNum: 3.00000000000000
+ Precision: -3
+)
+
+(LClass.50
+ Label: "3"
+ MinNum: 4.00000000000000
+ MaxNum: 8.00000000000000
+ Precision: -3
+)
+
+(LClass.51
+ IsNoData: 1
+ Label: "Keine Daten"
+ MaxNum: -1.00000000000000
+ Precision: -3
+)
+
+(BLnSym.52
+ Color: 53
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.53
+ Name: "Transparent"
+)
+
+(NameDict.54
+)
+
+(NameDict.55
+)
+
+(Thresh.56
+)
+
+(GSet.57
+)
+
+(TxPosArc.58
+ HAlign: 3
+ VAlign: 1
+)
+
+(AttrSingle.59
+ FTab: 23
+ Field: 25
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.60
+ FTab: 23
+ Field: 26
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.61
+ FTab: 23
+ Field: 27
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.62
+ FTab: 23
+ Field: 28
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.63
+ FTab: 23
+ Field: 29
+ UnionRule: 6
+ SplitRule: 4
+)
+
+(AttrSingle.64
+ FTab: 23
+ Field: 30
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.65
+ FTab: 23
+ Field: 31
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.66
+ FTab: 23
+ Field: 32
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.67
+ FTab: 23
+ Field: 33
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(FTheme.68
+ Name: "Cultural Landmarks"
+ Source: 69
+ Flags: 0x06
+ Legend: 83
+ Threshold: 151
+ View: 6
+ GSet: 152
+ LegEditScript: "View.EditLegend"
+ TxPos: 153
+ LabelField: 78
+ SnapTolCursor: 1
+)
+
+(ShpSrc.69
+ Name: 70
+ FTab: 72
+)
+
+(SrcName.70
+ FileName: 71
+ Name: "cultural_landmark-point.shp"
+ SubName: "Point"
+ OwnerClass: "ShpSrc"
+)
+
+(FN.71
+ Path: "Data/iceland/cultural_landmark-point.shp"
+)
+
+(FTab.72
+ Name: "cultural_landmark-point.dbf"
+ BTab: 73
+ Fields: 81
+ Fields: 74
+ Fields: 75
+ Fields: 76
+ Fields: 77
+ Fields: 78
+ Fields: 79
+ SelBits: 82
+ FSrc: 69
+)
+
+(dBASE.73
+ Name: "cultural_landmark-point.dbf"
+ Fields: 74
+ Fields: 75
+ Fields: 76
+ Fields: 77
+ Fields: 78
+ Fields: 79
+ FileName: 80
+)
+
+(Field.74
+ Name: "Area"
+ Btab: 73
+ Alias: "Area"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.75
+ Name: "Perimeter"
+ Btab: 73
+ Alias: "Perimeter"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.76
+ Name: "Clpoint_"
+ Btab: 73
+ Alias: "Clpoint_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.77
+ Name: "Clpoint_id"
+ Btab: 73
+ Alias: "Clpoint_id"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.78
+ Name: "Clptlabel"
+ Btab: 73
+ Alias: "Clptlabel"
+ Visible: 1
+ Type: 4
+ Order: -1
+)
+
+(Field.79
+ Name: "Clptflag"
+ Btab: 73
+ Alias: "Clptflag"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(FN.80
+ Path: "Data/iceland/cultural_landmark-point.dbf"
+)
+
+(Field.81
+ Name: "Shape"
+ Alias: "Shape"
+ Visible: 1
+ Type: 17
+ Order: -1
+)
+
+(Bitmap.82
+ NumBits: 34
+
+)
+
+(Legend.83
+ LegType: 0x08
+ ClassType: 0x03
+ FieldNames: 84
+ Symbols: 85
+ Class: 135
+ Class: 136
+ Class: 137
+ Class: 138
+ Class: 139
+ Class: 140
+ Class: 141
+ StdDevs: 1.00000000000000
+ NullSym: 142
+ NullValues: 149
+ StatValues: 150
+ Precision: -3
+)
+
+(AVStr.84
+ S: "Clptlabel"
+)
+
+(SymList.85
+ Child: 86
+ Child: 93
+ Child: 100
+ Child: 107
+ Child: 114
+ Child: 121
+ Child: 128
+)
+
+(BMkSym.86
+ Color: 87
+ BgColor: 88
+ Font: 89
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.87
+ Red: 0xffff
+)
+
+(TClr.88
+ Name: "Transparent"
+)
+
+(NFont.89
+ Family: 90
+ Name: 91
+ Style: 92
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.90
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.91
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.92
+ S: "Normal"
+)
+
+(BMkSym.93
+ Color: 94
+ BgColor: 95
+ Font: 96
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.94
+ Red: 0xa100
+ Green: 0x6686
+ Blue: 0x32f0
+)
+
+(TClr.95
+ Name: "Transparent"
+)
+
+(NFont.96
+ Family: 97
+ Name: 98
+ Style: 99
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.97
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.98
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.99
+ S: "Normal"
+)
+
+(BMkSym.100
+ Color: 101
+ BgColor: 102
+ Font: 103
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.101
+ Red: 0xd9d
+ Green: 0x81
+ Blue: 0x8200
+)
+
+(TClr.102
+ Name: "Transparent"
+)
+
+(NFont.103
+ Family: 104
+ Name: 105
+ Style: 106
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.104
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.105
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.106
+ S: "Normal"
+)
+
+(BMkSym.107
+ Color: 108
+ BgColor: 109
+ Font: 110
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.108
+ Red: 0xffff
+ Green: 0xffff
+)
+
+(TClr.109
+ Name: "Transparent"
+)
+
+(NFont.110
+ Family: 111
+ Name: 112
+ Style: 113
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.111
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.112
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.113
+ S: "Normal"
+)
+
+(BMkSym.114
+ Color: 115
+ BgColor: 116
+ Font: 117
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.115
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(TClr.116
+ Name: "Transparent"
+)
+
+(NFont.117
+ Family: 118
+ Name: 119
+ Style: 120
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.118
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.119
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.120
+ S: "Normal"
+)
+
+(BMkSym.121
+ Color: 122
+ BgColor: 123
+ Font: 124
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.122
+)
+
+(TClr.123
+ Name: "Transparent"
+)
+
+(NFont.124
+ Family: 125
+ Name: 126
+ Style: 127
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.125
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.126
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.127
+ S: "Normal"
+)
+
+(BMkSym.128
+ Color: 129
+ BgColor: 130
+ Font: 131
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.129
+ Name: "Transparent"
+)
+
+(TClr.130
+ Name: "Transparent"
+)
+
+(NFont.131
+ Family: 132
+ Name: 133
+ Style: 134
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.132
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.133
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.134
+ S: "Normal"
+)
+
+(LClass.135
+ IsText: 1
+ Label: "BUILDING"
+ MinStr: "BUILDING"
+ MaxStr: "BUILDING"
+ Precision: -3
+)
+
+(LClass.136
+ IsText: 1
+ Label: "FARM"
+ MinStr: "FARM"
+ MaxStr: "FARM"
+ Precision: -3
+)
+
+(LClass.137
+ IsText: 1
+ Label: "HUT"
+ MinStr: "HUT"
+ MaxStr: "HUT"
+ Precision: -3
+)
+
+(LClass.138
+ IsText: 1
+ Label: "LIGHTHOUSE"
+ MinStr: "LIGHTHOUSE"
+ MaxStr: "LIGHTHOUSE"
+ Precision: -3
+)
+
+(LClass.139
+ IsText: 1
+ Label: "OTHER/UNKNOWN"
+ MinStr: "OTHER/UNKNOWN"
+ MaxStr: "OTHER/UNKNOWN"
+ Precision: -3
+)
+
+(LClass.140
+ IsText: 1
+ Label: "RUINS"
+ MinStr: "RUINS"
+ MaxStr: "RUINS"
+ Precision: -3
+)
+
+(LClass.141
+ IsNoData: 1
+ IsText: 1
+ Label: "Keine Daten"
+ Precision: -3
+)
+
+(BMkSym.142
+ Color: 143
+ BgColor: 144
+ Font: 145
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.143
+ Name: "Transparent"
+)
+
+(TClr.144
+ Name: "Transparent"
+)
+
+(NFont.145
+ Family: 146
+ Name: 147
+ Style: 148
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.146
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.147
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.148
+ S: "Normal"
+)
+
+(NameDict.149
+)
+
+(NameDict.150
+)
+
+(Thresh.151
+)
+
+(GSet.152
+)
+
+(TxPosPt.153
+ HAlign: 4
+ VAlign: 3
+)
+
+(FTheme.154
+ Name: "Political Map"
+ Source: 155
+ Flags: 0x07
+ Legend: 171
+ Threshold: 184
+ View: 6
+ GSet: 185
+ LegEditScript: "View.EditLegend"
+ TxPos: 186
+ LabelField: 165
+ AttrRules: 187
+ AttrRules: 188
+ AttrRules: 189
+ AttrRules: 190
+ AttrRules: 191
+ AttrRules: 192
+ AttrRules: 193
+ AttrRules: 194
+ SnapTolCursor: 1
+)
+
+(ShpSrc.155
+ Name: 156
+ FTab: 158
+)
+
+(SrcName.156
+ FileName: 157
+ Name: "political.shp"
+ SubName: "Polygon"
+ OwnerClass: "ShpSrc"
+)
+
+(FN.157
+ Path: "Data/iceland/political.shp"
+)
+
+(FTab.158
+ Name: "political.dbf"
+ BTab: 159
+ Fields: 169
+ Fields: 160
+ Fields: 161
+ Fields: 162
+ Fields: 163
+ Fields: 164
+ Fields: 165
+ Fields: 166
+ Fields: 167
+ SelBits: 170
+ FSrc: 155
+)
+
+(dBASE.159
+ Name: "political.dbf"
+ Fields: 160
+ Fields: 161
+ Fields: 162
+ Fields: 163
+ Fields: 164
+ Fields: 165
+ Fields: 166
+ Fields: 167
+ FileName: 168
+)
+
+(Field.160
+ Name: "Area"
+ Btab: 159
+ Alias: "Area"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.161
+ Name: "Perimeter"
+ Btab: 159
+ Alias: "Perimeter"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.162
+ Name: "Ponet_"
+ Btab: 159
+ Alias: "Ponet_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.163
+ Name: "Ponet_id"
+ Btab: 159
+ Alias: "Ponet_id"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.164
+ Name: "Popytype"
+ Btab: 159
+ Alias: "Popytype"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.165
+ Name: "Popyreg"
+ Btab: 159
+ Alias: "Popyreg"
+ Visible: 1
+ Type: 4
+ Order: -1
+)
+
+(Field.166
+ Name: "Popycoun"
+ Btab: 159
+ Alias: "Popycoun"
+ Visible: 1
+ Type: 4
+ Order: -1
+)
+
+(Field.167
+ Name: "Popyadmin"
+ Btab: 159
+ Alias: "Popyadmin"
+ Visible: 1
+ Type: 4
+ Order: -1
+)
+
+(FN.168
+ Path: "Data/iceland/political.dbf"
+)
+
+(Field.169
+ Name: "Shape"
+ Alias: "Shape"
+ Visible: 1
+ Type: 19
+ Order: -1
+)
+
+(Bitmap.170
+ NumBits: 156
+
+)
+
+(Legend.171
+ SymType: 0x02
+ LegType: 0x01
+ ClassType: 0x03
+ Symbols: 172
+ Class: 177
+ StdDevs: 1.00000000000000
+ NullSym: 178
+ NullValues: 182
+ StatValues: 183
+ Precision: -3
+)
+
+(SymList.172
+ Child: 173
+)
+
+(BShSym.173
+ Color: 174
+ Outline: 1
+ OutlineColor: 175
+ OutlineWidth: 0.10000000000000
+ BgColor: 176
+)
+
+(TClr.174
+ Red: 0x12e
+ Green: 0x6400
+ Blue: 0x63
+)
+
+(TClr.175
+)
+
+(TClr.176
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(LClass.177
+ IsText: 1
+ Precision: -3
+)
+
+(BShSym.178
+ Color: 179
+ Outline: 1
+ OutlineColor: 180
+ OutlineWidth: 0.10000000000000
+ BgColor: 181
+)
+
+(TClr.179
+ Name: "Transparent"
+)
+
+(TClr.180
+ Name: "Transparent"
+)
+
+(TClr.181
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(NameDict.182
+)
+
+(NameDict.183
+)
+
+(Thresh.184
+)
+
+(GSet.185
+)
+
+(TxPosPly.186
+ HAlign: 3
+ VAlign: 3
+)
+
+(AttrSingle.187
+ FTab: 158
+ Field: 160
+ UnionRule: 5
+ SplitRule: 3
+)
+
+(AttrSingle.188
+ FTab: 158
+ Field: 161
+ UnionRule: 6
+ SplitRule: 4
+)
+
+(AttrSingle.189
+ FTab: 158
+ Field: 162
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.190
+ FTab: 158
+ Field: 163
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.191
+ FTab: 158
+ Field: 164
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.192
+ FTab: 158
+ Field: 165
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.193
+ FTab: 158
+ Field: 166
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.194
+ FTab: 158
+ Field: 167
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(View.195
+ Name: "View of Iceland with Cultural Landmarks and Roads"
+ Creator: "Test A. Little"
+ CreationDate: "Montag, 15. September 2003 10:27:38"
+ GUIName: "View"
+ Win: 196
+ CSMgr: 197
+ DocExts: 199
+ DocExts: 200
+ Graphics: 201
+ Theme: 208
+ Theme: 257
+ Theme: 343
+ LastScale: 4636161.54196571090000
+ Dpy: 202
+ TOCWidth: 150
+ CoordPrecision: 2
+)
+
+(DocWin.196
+ Owner: 195
+ X: -4
+ Y: -4
+ W: 1034
+ H: 643
+)
+
+(CSMgr.197
+ Client: 198
+)
+
+(CSClient.198
+ Client: 199
+ ReqName: "ClientNfy"
+)
+
+(PanMgr.199
+ Doc: 195
+)
+
+(DocAct.200
+ Doc: 195
+)
+
+(GList.201
+ Dpy: 202
+ FormatNumb: 207
+)
+
+(MapDpy.202
+ Left: -22.73219300137291
+ Bottom: 63.85512158261069
+ Top: 66.57720867977865
+ Right: -13.14576248989830
+ ReportUnits: 4
+ Units: 10
+ Scale: 203
+ FrameTop: 6.37500000000000
+ FrameRight: 9.05208333333333
+ PageDpy: 204
+ FitToPage: 1
+ MouseLoc: 206
+)
+
+(Numb.203
+ N: 0.94426004783515
+)
+
+(PageDpy.204
+ Top: 6.37500000000000
+ Right: 9.05208333333333
+ ReportUnits: 1
+ Units: 1
+ Scale: 205
+ ZoomRight: 9.05208333333333
+ ZoomTop: 6.37500000000000
+ GridSpacingX: 0.25000000000000
+ GridSpacingY: 0.25000000000000
+)
+
+(Numb.205
+ N: 0.11047180667434
+)
+
+(PointD.206
+ x: -13.36639380201509
+ y: 68.49254011612904
+)
+
+(Numb.207
+)
+
+(FTheme.208
+ Name: "Roads"
+ Source: 209
+ Flags: 0x06
+ Legend: 226
+ Threshold: 245
+ View: 195
+ GSet: 246
+ LegEditScript: "View.EditLegend"
+ TxPos: 247
+ AttrRules: 248
+ AttrRules: 249
+ AttrRules: 250
+ AttrRules: 251
+ AttrRules: 252
+ AttrRules: 253
+ AttrRules: 254
+ AttrRules: 255
+ AttrRules: 256
+ SnapTolCursor: 1
+)
+
+(ShpSrc.209
+ Name: 210
+ FTab: 212
+)
+
+(SrcName.210
+ FileName: 211
+ Name: "roads-line.shp"
+ SubName: "Arc"
+ OwnerClass: "ShpSrc"
+)
+
+(FN.211
+ Path: "Data/iceland/roads-line.shp"
+)
+
+(FTab.212
+ Name: "roads-line.dbf"
+ BTab: 213
+ Fields: 224
+ Fields: 214
+ Fields: 215
+ Fields: 216
+ Fields: 217
+ Fields: 218
+ Fields: 219
+ Fields: 220
+ Fields: 221
+ Fields: 222
+ SelBits: 225
+ FSrc: 209
+)
+
+(dBASE.213
+ Name: "roads-line.dbf"
+ Fields: 214
+ Fields: 215
+ Fields: 216
+ Fields: 217
+ Fields: 218
+ Fields: 219
+ Fields: 220
+ Fields: 221
+ Fields: 222
+ FileName: 223
+)
+
+(Field.214
+ Name: "Fnode_"
+ Btab: 213
+ Alias: "Fnode_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.215
+ Name: "Tnode_"
+ Btab: 213
+ Alias: "Tnode_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.216
+ Name: "Lpoly_"
+ Btab: 213
+ Alias: "Lpoly_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.217
+ Name: "Rpoly_"
+ Btab: 213
+ Alias: "Rpoly_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.218
+ Name: "Length"
+ Btab: 213
+ Alias: "Length"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.219
+ Name: "Rdline_"
+ Btab: 213
+ Alias: "Rdline_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.220
+ Name: "Rdline_id"
+ Btab: 213
+ Alias: "Rdline_id"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.221
+ Name: "Rdlntype"
+ Btab: 213
+ Alias: "Rdlntype"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.222
+ Name: "Rdlnstat"
+ Btab: 213
+ Alias: "Rdlnstat"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(FN.223
+ Path: "Data/iceland/roads-line.dbf"
+)
+
+(Field.224
+ Name: "Shape"
+ Alias: "Shape"
+ Visible: 1
+ Type: 18
+ Order: -1
+)
+
+(Bitmap.225
+ NumBits: 839
+
+)
+
+(Legend.226
+ SymType: 0x01
+ LegType: 0x02
+ ClassType: 0x03
+ FieldNames: 227
+ Symbols: 228
+ Class: 237
+ Class: 238
+ Class: 239
+ Class: 240
+ StdDevs: 1.00000000000000
+ NullSym: 241
+ NullValues: 243
+ StatValues: 244
+ Precision: -3
+)
+
+(AVStr.227
+ S: "Rdlntype"
+)
+
+(SymList.228
+ Child: 229
+ Child: 231
+ Child: 233
+ Child: 235
+)
+
+(BLnSym.229
+ Color: 230
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.230
+)
+
+(BLnSym.231
+ Color: 232
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.232
+ Red: 0xa5a5
+ Green: 0xa5a5
+ Blue: 0xa5a5
+)
+
+(BLnSym.233
+ Color: 234
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.234
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(BLnSym.235
+ Color: 236
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.236
+ Name: "Transparent"
+)
+
+(LClass.237
+ Label: "1"
+ MinNum: 2.00000000000000
+ MaxNum: 2.00000000000000
+ Precision: -3
+)
+
+(LClass.238
+ Label: "2"
+ MinNum: 3.00000000000000
+ MaxNum: 3.00000000000000
+ Precision: -3
+)
+
+(LClass.239
+ Label: "3"
+ MinNum: 4.00000000000000
+ MaxNum: 8.00000000000000
+ Precision: -3
+)
+
+(LClass.240
+ IsNoData: 1
+ Label: "Keine Daten"
+ MaxNum: -1.00000000000000
+ Precision: -3
+)
+
+(BLnSym.241
+ Color: 242
+ Width: 0.10000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+ Pattern: 0.00000000000000
+)
+
+(TClr.242
+ Name: "Transparent"
+)
+
+(NameDict.243
+)
+
+(NameDict.244
+)
+
+(Thresh.245
+)
+
+(GSet.246
+)
+
+(TxPosArc.247
+ HAlign: 3
+ VAlign: 1
+)
+
+(AttrSingle.248
+ FTab: 212
+ Field: 214
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.249
+ FTab: 212
+ Field: 215
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.250
+ FTab: 212
+ Field: 216
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.251
+ FTab: 212
+ Field: 217
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.252
+ FTab: 212
+ Field: 218
+ UnionRule: 6
+ SplitRule: 4
+)
+
+(AttrSingle.253
+ FTab: 212
+ Field: 219
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.254
+ FTab: 212
+ Field: 220
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.255
+ FTab: 212
+ Field: 221
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(AttrSingle.256
+ FTab: 212
+ Field: 222
+ UnionRule: 1
+ SplitRule: 1
+)
+
+(FTheme.257
+ Name: "Cultural Landmarks"
+ Source: 258
+ Flags: 0x06
+ Legend: 272
+ Threshold: 340
+ View: 195
+ GSet: 341
+ LegEditScript: "View.EditLegend"
+ TxPos: 342
+ LabelField: 267
+ SnapTolCursor: 1
+)
+
+(ShpSrc.258
+ Name: 259
+ FTab: 261
+)
+
+(SrcName.259
+ FileName: 260
+ Name: "cultural_landmark-point.shp"
+ SubName: "Point"
+ OwnerClass: "ShpSrc"
+)
+
+(FN.260
+ Path: "Data/iceland/cultural_landmark-point.shp"
+)
+
+(FTab.261
+ Name: "cultural_landmark-point.dbf"
+ BTab: 262
+ Fields: 270
+ Fields: 263
+ Fields: 264
+ Fields: 265
+ Fields: 266
+ Fields: 267
+ Fields: 268
+ SelBits: 271
+ FSrc: 258
+)
+
+(dBASE.262
+ Name: "cultural_landmark-point.dbf"
+ Fields: 263
+ Fields: 264
+ Fields: 265
+ Fields: 266
+ Fields: 267
+ Fields: 268
+ FileName: 269
+)
+
+(Field.263
+ Name: "Area"
+ Btab: 262
+ Alias: "Area"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.264
+ Name: "Perimeter"
+ Btab: 262
+ Alias: "Perimeter"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.265
+ Name: "Clpoint_"
+ Btab: 262
+ Alias: "Clpoint_"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.266
+ Name: "Clpoint_id"
+ Btab: 262
+ Alias: "Clpoint_id"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(Field.267
+ Name: "Clptlabel"
+ Btab: 262
+ Alias: "Clptlabel"
+ Visible: 1
+ Type: 4
+ Order: -1
+)
+
+(Field.268
+ Name: "Clptflag"
+ Btab: 262
+ Alias: "Clptflag"
+ Visible: 1
+ Type: 9
+ Order: -1
+)
+
+(FN.269
+ Path: "Data/iceland/cultural_landmark-point.dbf"
+)
+
+(Field.270
+ Name: "Shape"
+ Alias: "Shape"
+ Visible: 1
+ Type: 17
+ Order: -1
+)
+
+(Bitmap.271
+ NumBits: 34
+
+)
+
+(Legend.272
+ LegType: 0x08
+ ClassType: 0x03
+ FieldNames: 273
+ Symbols: 274
+ Class: 324
+ Class: 325
+ Class: 326
+ Class: 327
+ Class: 328
+ Class: 329
+ Class: 330
+ StdDevs: 1.00000000000000
+ NullSym: 331
+ NullValues: 338
+ StatValues: 339
+ Precision: -3
+)
+
+(AVStr.273
+ S: "Clptlabel"
+)
+
+(SymList.274
+ Child: 275
+ Child: 282
+ Child: 289
+ Child: 296
+ Child: 303
+ Child: 310
+ Child: 317
+)
+
+(BMkSym.275
+ Color: 276
+ BgColor: 277
+ Font: 278
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.276
+ Red: 0xffff
+)
+
+(TClr.277
+ Name: "Transparent"
+)
+
+(NFont.278
+ Family: 279
+ Name: 280
+ Style: 281
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.279
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.280
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.281
+ S: "Normal"
+)
+
+(BMkSym.282
+ Color: 283
+ BgColor: 284
+ Font: 285
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.283
+ Red: 0xa100
+ Green: 0x6686
+ Blue: 0x32f0
+)
+
+(TClr.284
+ Name: "Transparent"
+)
+
+(NFont.285
+ Family: 286
+ Name: 287
+ Style: 288
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.286
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.287
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.288
+ S: "Normal"
+)
+
+(BMkSym.289
+ Color: 290
+ BgColor: 291
+ Font: 292
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.290
+ Red: 0x170b
+ Green: 0xdb
+ Blue: 0xdc00
+)
+
+(TClr.291
+ Name: "Transparent"
+)
+
+(NFont.292
+ Family: 293
+ Name: 294
+ Style: 295
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.293
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.294
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.295
+ S: "Normal"
+)
+
+(BMkSym.296
+ Color: 297
+ BgColor: 298
+ Font: 299
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.297
+ Red: 0xffff
+ Green: 0xffff
+)
+
+(TClr.298
+ Name: "Transparent"
+)
+
+(NFont.299
+ Family: 300
+ Name: 301
+ Style: 302
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.300
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.301
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.302
+ S: "Normal"
+)
+
+(BMkSym.303
+ Color: 304
+ BgColor: 305
+ Font: 306
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.304
+ Red: 0xffff
+ Green: 0xffff
+ Blue: 0xffff
+)
+
+(TClr.305
+ Name: "Transparent"
+)
+
+(NFont.306
+ Family: 307
+ Name: 308
+ Style: 309
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.307
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.308
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.309
+ S: "Normal"
+)
+
+(BMkSym.310
+ Color: 311
+ BgColor: 312
+ Font: 313
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.311
+)
+
+(TClr.312
+ Name: "Transparent"
+)
+
+(NFont.313
+ Family: 314
+ Name: 315
+ Style: 316
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.314
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.315
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.316
+ S: "Normal"
+)
+
+(BMkSym.317
+ Color: 318
+ BgColor: 319
+ Font: 320
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.318
+ Name: "Transparent"
+)
+
+(TClr.319
+ Name: "Transparent"
+)
+
+(NFont.320
+ Family: 321
+ Name: 322
+ Style: 323
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.321
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.322
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.323
+ S: "Normal"
+)
+
+(LClass.324
+ IsText: 1
+ Label: "BUILDING"
+ MinStr: "BUILDING"
+ MaxStr: "BUILDING"
+ Precision: -3
+)
+
+(LClass.325
+ IsText: 1
+ Label: "FARM"
+ MinStr: "FARM"
+ MaxStr: "FARM"
+ Precision: -3
+)
+
+(LClass.326
+ IsText: 1
+ Label: "HUT"
+ MinStr: "HUT"
+ MaxStr: "HUT"
+ Precision: -3
+)
+
+(LClass.327
+ IsText: 1
+ Label: "LIGHTHOUSE"
+ MinStr: "LIGHTHOUSE"
+ MaxStr: "LIGHTHOUSE"
+ Precision: -3
+)
+
+(LClass.328
+ IsText: 1
+ Label: "OTHER/UNKNOWN"
+ MinStr: "OTHER/UNKNOWN"
+ MaxStr: "OTHER/UNKNOWN"
+ Precision: -3
+)
+
+(LClass.329
+ IsText: 1
+ Label: "RUINS"
+ MinStr: "RUINS"
+ MaxStr: "RUINS"
+ Precision: -3
+)
+
+(LClass.330
+ IsNoData: 1
+ IsText: 1
+ Label: "Keine Daten"
+ Precision: -3
+)
+
+(BMkSym.331
+ Color: 332
+ BgColor: 333
+ Font: 334
+ Size: 8.00000000000000
+ Pattern: 35
+ Angle: 360.00000000000000
+)
+
+(TClr.332
+ Name: "Transparent"
+)
+
+(TClr.333
+ Name: "Transparent"
+)
+
+(NFont.334
+ Family: 335
+ Name: 336
+ Style: 337
+ Weight: 1
+ Wideness: 1
+)
+
+(AVStr.335
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.336
+ S: "ESRI Geometric Symbols"
+)
+
+(AVStr.337
+ S: "Normal"
+)
+
+(NameDict.338
+)
+
+(NameDict.339
+)
+
+(Thresh.340
+)
+
+(GSet.341
+)
+
+(TxPosPt.342
+ HAlign: 4
+ VAlign: 3
+)
+
+(ITheme.343
+ Name: "Iceland"
+ Source: 344
+ Flags: 0x07
+ Legend: 349
+ Threshold: 609
+ View: 195
+ GSet: 610
+ LegEditScript: "View.EditLegend"
+)
+
+(ISrc.344
+ Name: 345
+ MapBox: 347
+ BandStats: 348
+)
+
+(SrcName.345
+ FileName: 346
+ Name: "island.tif"
+ OwnerClass: "ISrc"
+)
+
+(FN.346
+ Path: "Data/iceland/island.tif"
+)
+
+(RectD.347
+ Left: -24.55000000000000
+ Top: 66.56666700000000
+ Right: -13.49166700000083
+ Bottom: 63.28333299999988
+)
+
+(BStat.348
+ Max: 255.00000000000000
+ Mean: 127.50000000000000
+ StDv: 63.75000000000000
+)
+
+(SBILeg.349
+ PixelLUT: 350
+ ClrMap: 351
+)
+
+(ILUTIdn.350
+)
+
+(TClrMap.351
+ Colors: 352
+ Colors: 353
+ Colors: 354
+ Colors: 355
+ Colors: 356
+ Colors: 357
+ Colors: 358
+ Colors: 359
+ Colors: 360
+ Colors: 361
+ Colors: 362
+ Colors: 363
+ Colors: 364
+ Colors: 365
+ Colors: 366
+ Colors: 367
+ Colors: 368
+ Colors: 369
+ Colors: 370
+ Colors: 371
+ Colors: 372
+ Colors: 373
+ Colors: 374
+ Colors: 375
+ Colors: 376
+ Colors: 377
+ Colors: 378
+ Colors: 379
+ Colors: 380
+ Colors: 381
+ Colors: 382
+ Colors: 383
+ Colors: 384
+ Colors: 385
+ Colors: 386
+ Colors: 387
+ Colors: 388
+ Colors: 389
+ Colors: 390
+ Colors: 391
+ Colors: 392
+ Colors: 393
+ Colors: 394
+ Colors: 395
+ Colors: 396
+ Colors: 397
+ Colors: 398
+ Colors: 399
+ Colors: 400
+ Colors: 401
+ Colors: 402
+ Colors: 403
+ Colors: 404
+ Colors: 405
+ Colors: 406
+ Colors: 407
+ Colors: 408
+ Colors: 409
+ Colors: 410
+ Colors: 411
+ Colors: 412
+ Colors: 413
+ Colors: 414
+ Colors: 415
+ Colors: 416
+ Colors: 417
+ Colors: 418
+ Colors: 419
+ Colors: 420
+ Colors: 421
+ Colors: 422
+ Colors: 423
+ Colors: 424
+ Colors: 425
+ Colors: 426
+ Colors: 427
+ Colors: 428
+ Colors: 429
+ Colors: 430
+ Colors: 431
+ Colors: 432
+ Colors: 433
+ Colors: 434
+ Colors: 435
+ Colors: 436
+ Colors: 437
+ Colors: 438
+ Colors: 439
+ Colors: 440
+ Colors: 441
+ Colors: 442
+ Colors: 443
+ Colors: 444
+ Colors: 445
+ Colors: 446
+ Colors: 447
+ Colors: 448
+ Colors: 449
+ Colors: 450
+ Colors: 451
+ Colors: 452
+ Colors: 453
+ Colors: 454
+ Colors: 455
+ Colors: 456
+ Colors: 457
+ Colors: 458
+ Colors: 459
+ Colors: 460
+ Colors: 461
+ Colors: 462
+ Colors: 463
+ Colors: 464
+ Colors: 465
+ Colors: 466
+ Colors: 467
+ Colors: 468
+ Colors: 469
+ Colors: 470
+ Colors: 471
+ Colors: 472
+ Colors: 473
+ Colors: 474
+ Colors: 475
+ Colors: 476
+ Colors: 477
+ Colors: 478
+ Colors: 479
+ Colors: 480
+ Colors: 481
+ Colors: 482
+ Colors: 483
+ Colors: 484
+ Colors: 485
+ Colors: 486
+ Colors: 487
+ Colors: 488
+ Colors: 489
+ Colors: 490
+ Colors: 491
+ Colors: 492
+ Colors: 493
+ Colors: 494
+ Colors: 495
+ Colors: 496
+ Colors: 497
+ Colors: 498
+ Colors: 499
+ Colors: 500
+ Colors: 501
+ Colors: 502
+ Colors: 503
+ Colors: 504
+ Colors: 505
+ Colors: 506
+ Colors: 507
+ Colors: 508
+ Colors: 509
+ Colors: 510
+ Colors: 511
+ Colors: 512
+ Colors: 513
+ Colors: 514
+ Colors: 515
+ Colors: 516
+ Colors: 517
+ Colors: 518
+ Colors: 519
+ Colors: 520
+ Colors: 521
+ Colors: 522
+ Colors: 523
+ Colors: 524
+ Colors: 525
+ Colors: 526
+ Colors: 527
+ Colors: 528
+ Colors: 529
+ Colors: 530
+ Colors: 531
+ Colors: 532
+ Colors: 533
+ Colors: 534
+ Colors: 535
+ Colors: 536
+ Colors: 537
+ Colors: 538
+ Colors: 539
+ Colors: 540
+ Colors: 541
+ Colors: 542
+ Colors: 543
+ Colors: 544
+ Colors: 545
+ Colors: 546
+ Colors: 547
+ Colors: 548
+ Colors: 549
+ Colors: 550
+ Colors: 551
+ Colors: 552
+ Colors: 553
+ Colors: 554
+ Colors: 555
+ Colors: 556
+ Colors: 557
+ Colors: 558
+ Colors: 559
+ Colors: 560
+ Colors: 561
+ Colors: 562
+ Colors: 563
+ Colors: 564
+ Colors: 565
+ Colors: 566
+ Colors: 567
+ Colors: 568
+ Colors: 569
+ Colors: 570
+ Colors: 571
+ Colors: 572
+ Colors: 573
+ Colors: 574
+ Colors: 575
+ Colors: 576
+ Colors: 577
+ Colors: 578
+ Colors: 579
+ Colors: 580
+ Colors: 581
+ Colors: 582
+ Colors: 583
+ Colors: 584
+ Colors: 585
+ Colors: 586
+ Colors: 587
+ Colors: 588
+ Colors: 589
+ Colors: 590
+ Colors: 591
+ Colors: 592
+ Colors: 593
+ Colors: 594
+ Colors: 595
+ Colors: 596
+ Colors: 597
+ Colors: 598
+ Colors: 599
+ Colors: 600
+ Colors: 601
+ Colors: 602
+ Colors: 603
+ Colors: 604
+ Colors: 605
+ Colors: 606
+ Colors: 607
+ NoDataClr: 608
+)
+
+(TClr.352
+ Red: 0xe00
+ Green: 0x9600
+ Blue: 0x200
+)
+
+(TClr.353
+ Red: 0x200
+ Green: 0xc600
+ Blue: 0x200
+)
+
+(TClr.354
+ Red: 0x3a00
+ Green: 0x7e00
+ Blue: 0x600
+)
+
+(TClr.355
+ Red: 0x7200
+ Green: 0x6600
+ Blue: 0x1e00
+)
+
+(TClr.356
+ Red: 0x7a00
+ Green: 0x7600
+ Blue: 0x2600
+)
+
+(TClr.357
+ Red: 0x8e00
+ Green: 0x8e00
+ Blue: 0x2e00
+)
+
+(TClr.358
+ Red: 0x200
+ Green: 0xb200
+ Blue: 0x200
+)
+
+(TClr.359
+ Red: 0x1a00
+ Green: 0xba00
+ Blue: 0x4e00
+)
+
+(TClr.360
+ Red: 0x200
+ Green: 0x9e00
+ Blue: 0x200
+)
+
+(TClr.361
+ Red: 0x5200
+ Green: 0x6600
+ Blue: 0xe600
+)
+
+(TClr.362
+ Red: 0x3600
+ Green: 0x8e00
+ Blue: 0x9a00
+)
+
+(TClr.363
+ Red: 0x200
+ Green: 0xce00
+ Blue: 0x200
+)
+
+(TClr.364
+ Red: 0x3200
+ Green: 0x8200
+ Blue: 0x200
+)
+
+(TClr.365
+ Red: 0x6600
+ Green: 0x6a00
+ Blue: 0x1600
+)
+
+(TClr.366
+ Red: 0xe600
+ Green: 0xe200
+ Blue: 0xe00
+)
+
+(TClr.367
+ Red: 0x200
+ Green: 0xd200
+ Blue: 0x200
+)
+
+(TClr.368
+ Red: 0x200
+ Green: 0xaa00
+ Blue: 0x200
+)
+
+(TClr.369
+ Red: 0x5a00
+ Green: 0x7200
+ Blue: 0x1200
+)
+
+(TClr.370
+ Red: 0x200
+ Green: 0xd600
+ Blue: 0x200
+)
+
+(TClr.371
+ Red: 0xa600
+ Green: 0x9e00
+ Blue: 0x3200
+)
+
+(TClr.372
+ Red: 0xde00
+ Green: 0xda00
+ Blue: 0x1200
+)
+
+(TClr.373
+ Red: 0x2200
+ Green: 0x8a00
+ Blue: 0x200
+)
+
+(TClr.374
+ Red: 0x200
+ Green: 0xda00
+ Blue: 0x200
+)
+
+(TClr.375
+ Red: 0x200
+ Green: 0xb600
+ Blue: 0x200
+)
+
+(TClr.376
+ Red: 0xce00
+ Green: 0xc600
+ Blue: 0x1e00
+)
+
+(TClr.377
+ Red: 0x4e00
+ Green: 0x7600
+ Blue: 0xa00
+)
+
+(TClr.378
+ Red: 0x200
+ Green: 0xa200
+ Blue: 0x200
+)
+
+(TClr.379
+ Red: 0xda00
+ Green: 0xd600
+ Blue: 0x1600
+)
+
+(TClr.380
+ Red: 0x8a00
+ Green: 0x8e00
+ Blue: 0x2a00
+)
+
+(TClr.381
+ Red: 0x7a00
+ Green: 0x7600
+ Blue: 0x2200
+)
+
+(TClr.382
+ Red: 0x200
+ Green: 0xe200
+ Blue: 0x200
+)
+
+(TClr.383
+ Red: 0xa200
+ Green: 0x9a00
+ Blue: 0x3200
+)
+
+(TClr.384
+ Red: 0x3a00
+ Green: 0x7e00
+ Blue: 0x200
+)
+
+(TClr.385
+ Red: 0x200
+ Green: 0xbe00
+ Blue: 0x200
+)
+
+(TClr.386
+ Red: 0x1600
+ Green: 0x9200
+ Blue: 0x200
+)
+
+(TClr.387
+ Red: 0x7a00
+ Green: 0x7e00
+ Blue: 0x2600
+)
+
+(TClr.388
+ Red: 0x1e00
+ Green: 0x8e00
+ Blue: 0x200
+)
+
+(TClr.389
+ Red: 0xd600
+ Green: 0xd200
+ Blue: 0x1a00
+)
+
+(TClr.390
+ Red: 0x7a00
+ Green: 0x6e00
+ Blue: 0x2200
+)
+
+(TClr.391
+ Red: 0xca00
+ Green: 0xc600
+ Blue: 0x1e00
+)
+
+(TClr.392
+ Red: 0x4a00
+ Green: 0x7a00
+ Blue: 0xa00
+)
+
+(TClr.393
+ Red: 0xe00
+ Green: 0x9a00
+ Blue: 0x200
+)
+
+(TClr.394
+ Red: 0xd200
+ Green: 0xce00
+ Blue: 0x1a00
+)
+
+(TClr.395
+ Red: 0xc600
+ Green: 0xc200
+ Blue: 0x2200
+)
+
+(TClr.396
+ Red: 0x8200
+ Green: 0x8a00
+ Blue: 0x2a00
+)
+
+(TClr.397
+ Red: 0x2a00
+ Green: 0x8600
+ Blue: 0x200
+)
+
+(TClr.398
+ Red: 0x4600
+ Green: 0x7a00
+ Blue: 0x600
+)
+
+(TClr.399
+ Red: 0xa00
+ Green: 0x9a00
+ Blue: 0x200
+)
+
+(TClr.400
+ Red: 0xba00
+ Green: 0xb200
+ Blue: 0x2a00
+)
+
+(TClr.401
+ Red: 0x200
+ Green: 0xe600
+ Blue: 0x200
+)
+
+(TClr.402
+ Red: 0x200
+ Green: 0xde00
+ Blue: 0x200
+)
+
+(TClr.403
+ Red: 0x1a00
+ Green: 0x9200
+ Blue: 0x200
+)
+
+(TClr.404
+ Red: 0x6a00
+ Green: 0x6a00
+ Blue: 0x1600
+)
+
+(TClr.405
+ Red: 0x600
+ Green: 0x9e00
+ Blue: 0x200
+)
+
+(TClr.406
+ Red: 0x2200
+ Green: 0x8e00
+ Blue: 0x200
+)
+
+(TClr.407
+ Red: 0x200
+ Green: 0xa600
+ Blue: 0x200
+)
+
+(TClr.408
+ Red: 0xc600
+ Green: 0xbe00
+ Blue: 0x2200
+)
+
+(TClr.409
+ Red: 0x7a00
+ Green: 0x8200
+ Blue: 0x2600
+)
+
+(TClr.410
+ Red: 0x200
+ Green: 0xc200
+ Blue: 0x200
+)
+
+(TClr.411
+ Red: 0x200
+ Green: 0xca00
+ Blue: 0x200
+)
+
+(TClr.412
+ Red: 0x200
+ Green: 0xae00
+ Blue: 0x200
+)
+
+(TClr.413
+ Red: 0x1200
+ Green: 0x9600
+ Blue: 0x200
+)
+
+(TClr.414
+ Red: 0x5600
+ Green: 0x7200
+ Blue: 0xe00
+)
+
+(TClr.415
+ Red: 0x9e00
+ Green: 0x9a00
+ Blue: 0x2e00
+)
+
+(TClr.416
+ Red: 0x200
+ Green: 0xba00
+ Blue: 0x200
+)
+
+(TClr.417
+ Red: 0x3600
+ Green: 0x8200
+ Blue: 0x200
+)
+
+(TClr.418
+ Red: 0x5e00
+ Green: 0x6e00
+ Blue: 0x1200
+)
+
+(TClr.419
+ Red: 0x2a00
+ Green: 0x8a00
+ Blue: 0x200
+)
+
+(TClr.420
+ Red: 0x4200
+ Green: 0x7a00
+ Blue: 0x600
+)
+
+(TClr.421
+ Red: 0x7a00
+ Green: 0x6a00
+ Blue: 0x1e00
+)
+
+(TClr.422
+ Red: 0x7200
+ Green: 0x6600
+ Blue: 0x1a00
+)
+
+(TClr.423
+ Red: 0x2e00
+ Green: 0x8600
+ Blue: 0x200
+)
+
+(TClr.424
+ Red: 0x9a00
+ Green: 0x9600
+ Blue: 0x2e00
+)
+
+(TClr.425
+ Red: 0x7a00
+ Green: 0x7200
+ Blue: 0x2200
+)
+
+(TClr.426
+ Red: 0x1600
+ Green: 0x9600
+ Blue: 0x200
+)
+
+(TClr.427
+ Red: 0x5e00
+ Green: 0x7200
+ Blue: 0x1200
+)
+
+(TClr.428
+ Red: 0x4200
+ Green: 0x7e00
+ Blue: 0x600
+)
+
+(TClr.429
+ Red: 0x8200
+ Green: 0x8600
+ Blue: 0x2a00
+)
+
+(TClr.430
+ Red: 0x5200
+ Green: 0x7600
+ Blue: 0xe00
+)
+
+(TClr.431
+ Red: 0x7600
+ Green: 0x6600
+ Blue: 0x1e00
+)
+
+(TClr.432
+ Red: 0x2600
+ Green: 0x8a00
+ Blue: 0x200
+)
+
+(TClr.433
+ Red: 0x7a00
+ Green: 0x7a00
+ Blue: 0x2600
+)
+
+(TClr.434
+ Red: 0x7a00
+ Green: 0x8600
+ Blue: 0x2a00
+)
+
+(TClr.435
+ Red: 0xb600
+ Green: 0xae00
+ Blue: 0x2a00
+)
+
+(TClr.436
+ Red: 0x6e00
+ Green: 0x6a00
+ Blue: 0x1a00
+)
+
+(TClr.437
+ Red: 0x7a00
+ Green: 0x6600
+ Blue: 0x1e00
+)
+
+(TClr.438
+ Red: 0x1e00
+ Green: 0x9200
+ Blue: 0x200
+)
+
+(TClr.439
+ Red: 0xb200
+ Green: 0xaa00
+ Blue: 0x2e00
+)
+
+(TClr.440
+ Red: 0x5600
+ Green: 0x7600
+ Blue: 0xe00
+)
+
+(TClr.441
+ Red: 0x9600
+ Green: 0x9600
+ Blue: 0x2e00
+)
+
+(TClr.442
+ Red: 0x3a00
+ Green: 0x8200
+ Blue: 0x200
+)
+
+(TClr.443
+ Red: 0x3e00
+ Green: 0x7e00
+ Blue: 0x600
+)
+
+(TClr.444
+ Red: 0x6200
+ Green: 0x6e00
+ Blue: 0x1200
+)
+
+(TClr.445
+ Red: 0x9600
+ Green: 0x9200
+ Blue: 0x2e00
+)
+
+(TClr.446
+ Red: 0xe600
+ Green: 0xe600
+ Blue: 0xe00
+)
+
+(TClr.447
+ Red: 0x6600
+ Green: 0x6e00
+ Blue: 0x1600
+)
+
+(TClr.448
+ Red: 0x7200
+ Green: 0x6a00
+ Blue: 0x1a00
+)
+
+(TClr.449
+ Red: 0x8e00
+ Green: 0x9200
+ Blue: 0x2e00
+)
+
+(TClr.450
+ Red: 0x8600
+ Green: 0x8a00
+ Blue: 0x2a00
+)
+
+(TClr.451
+ Red: 0x4e00
+ Green: 0x7600
+ Blue: 0xe00
+)
+
+(TClr.452
+ Red: 0xea00
+ Green: 0xea00
+ Blue: 0xe00
+)
+
+(TClr.453
+ Red: 0x7a00
+ Green: 0x6a00
+ Blue: 0x2200
+)
+
+(TClr.454
+ Red: 0xae00
+ Green: 0xa600
+ Blue: 0x2e00
+)
+
+(TClr.455
+ Red: 0x6a00
+ Green: 0x6a00
+ Blue: 0x1a00
+)
+
+(TClr.456
+ Red: 0x7a00
+ Green: 0x8200
+ Blue: 0x2a00
+)
+
+(TClr.457
+ Red: 0x5600
+ Green: 0x7200
+ Blue: 0x1200
+)
+
+(TClr.458
+ Red: 0x4600
+ Green: 0x7a00
+ Blue: 0xa00
+)
+
+(TClr.459
+ Red: 0x6200
+ Green: 0x6e00
+ Blue: 0x1600
+)
+
+(TClr.460
+ Red: 0xee00
+ Green: 0xee00
+ Blue: 0xa00
+)
+
+(TClr.461
+ Red: 0x7e00
+ Green: 0x8600
+ Blue: 0x2a00
+)
+
+(TClr.462
+ Red: 0x8a00
+ Green: 0x8a00
+ Blue: 0x2a00
+)
+
+(TClr.463
+ Red: 0xae00
+ Green: 0xa600
+ Blue: 0x3200
+)
+
+(TClr.464
+ Red: 0xf200
+ Green: 0xf200
+ Blue: 0x600
+)
+
+(TClr.465
+ Red: 0xc200
+ Green: 0xba00
+ Blue: 0x2600
+)
+
+(TClr.466
+ Red: 0xaa00
+ Green: 0x9e00
+ Blue: 0x3200
+)
+
+(TClr.467
+ Red: 0x9e00
+ Green: 0x9600
+ Blue: 0x2e00
+)
+
+(TClr.468
+ Red: 0xaa00
+ Green: 0xa200
+ Blue: 0x3200
+)
+
+(TClr.469
+ Red: 0xf600
+ Green: 0xf600
+ Blue: 0x600
+)
+
+(TClr.470
+ Red: 0x9200
+ Green: 0x9200
+ Blue: 0x2e00
+)
+
+(TClr.471
+ Red: 0xe200
+ Green: 0xde00
+ Blue: 0x1200
+)
+
+(TClr.472
+ Red: 0xbe00
+ Green: 0xb600
+ Blue: 0x2600
+)
+
+(TClr.473
+ Red: 0xce00
+ Green: 0xca00
+ Blue: 0x1e00
+)
+
+(TClr.474
+ Red: 0xa200
+ Green: 0x9e00
+ Blue: 0x3200
+)
+
+(TClr.475
+ Red: 0xb600
+ Green: 0xae00
+ Blue: 0x2e00
+)
+
+(TClr.476
+ Red: 0xae00
+ Green: 0xa200
+ Blue: 0x3200
+)
+
+(TClr.477
+ Red: 0xfa00
+ Green: 0xfa00
+ Blue: 0x200
+)
+
+(TClr.478
+ Red: 0xd200
+ Green: 0xca00
+ Blue: 0x1a00
+)
+
+(TClr.479
+ Red: 0xe200
+ Green: 0xe200
+ Blue: 0x1200
+)
+
+(TClr.480
+ Red: 0xf600
+ Green: 0xf200
+ Blue: 0x600
+)
+
+(TClr.481
+ Red: 0xea00
+ Green: 0xe600
+ Blue: 0xe00
+)
+
+(TClr.482
+ Red: 0xb600
+ Green: 0xaa00
+ Blue: 0x2e00
+)
+
+(TClr.483
+ Red: 0xb200
+ Green: 0xa600
+ Blue: 0x2e00
+)
+
+(TClr.484
+ Red: 0xfa00
+ Green: 0xf600
+ Blue: 0x600
+)
+
+(TClr.485
+ Red: 0xca00
+ Green: 0xc200
+ Blue: 0x2200
+)
+
+(TClr.486
+ Red: 0xde00
+ Green: 0xda00
+ Blue: 0x1600
+)
+
+(TClr.487
+ Red: 0xbe00
+ Green: 0xb600
+ Blue: 0x2a00
+)
+
+(TClr.488
+ Red: 0xf200
+ Green: 0xee00
+ Blue: 0xa00
+)
+
+(TClr.489
+ Red: 0xe600
+ Green: 0xe200
+ Blue: 0x1200
+)
+
+(TClr.490
+ Red: 0xee00
+ Green: 0xea00
+ Blue: 0xa00
+)
+
+(TClr.491
+ Red: 0xf200
+ Green: 0xf200
+ Blue: 0xa00
+)
+
+(TClr.492
+ Red: 0xfa00
+ Green: 0xfa00
+ Blue: 0x600
+)
+
+(TClr.493
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.494
+ Red: 0x6400
+ Green: 0x6400
+ Blue: 0x5800
+)
+
+(TClr.495
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.496
+ Red: 0x9f00
+ Green: 0x9e00
+ Blue: 0x600
+)
+
+(TClr.497
+ Red: 0x800
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.498
+ Red: 0xfc00
+ Green: 0x8000
+)
+
+(TClr.499
+ Red: 0xbf00
+ Green: 0xfb00
+)
+
+(TClr.500
+ Red: 0xa00
+ Green: 0x3d00
+ Blue: 0x9100
+)
+
+(TClr.501
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.502
+ Red: 0x4100
+ Green: 0x3d00
+ Blue: 0x2e00
+)
+
+(TClr.503
+ Red: 0x800
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.504
+ Green: 0x3c00
+ Blue: 0x600
+)
+
+(TClr.505
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.506
+ Red: 0xfa00
+ Green: 0x3c00
+ Blue: 0x600
+)
+
+(TClr.507
+ Red: 0xbf00
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.508
+ Red: 0x5700
+ Green: 0x3c00
+ Blue: 0x2500
+)
+
+(TClr.509
+ Red: 0x4000
+ Green: 0x800
+ Blue: 0x800
+)
+
+(TClr.510
+ Red: 0x4000
+ Green: 0x3c00
+)
+
+(TClr.511
+ Red: 0x800
+ Green: 0x800
+)
+
+(TClr.512
+ Red: 0x4000
+ Green: 0x3c00
+ Blue: 0x600
+)
+
+(TClr.513
+ Red: 0x800
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.514
+ Green: 0x6400
+)
+
+(TClr.515
+ Green: 0x4000
+)
+
+(TClr.516
+ Red: 0x9a00
+ Green: 0x2e00
+)
+
+(TClr.517
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.518
+ Red: 0x2e00
+)
+
+(TClr.519
+ Red: 0x4000
+)
+
+(TClr.520
+ Red: 0x600
+ Green: 0x4000
+ Blue: 0x600
+)
+
+(TClr.521
+ Red: 0x4000
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.522
+ Red: 0x4000
+ Blue: 0xf600
+)
+
+(TClr.523
+ Red: 0x800
+ Blue: 0xbf00
+)
+
+(TClr.524
+ Red: 0xd800
+ Green: 0x2e00
+ Blue: 0x9000
+)
+
+(TClr.525
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.526
+ Red: 0x3900
+ Green: 0x6400
+ Blue: 0x2e00
+)
+
+(TClr.527
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.528
+ Red: 0x9f00
+ Green: 0x9e00
+)
+
+(TClr.529
+ Red: 0x800
+ Green: 0x4000
+)
+
+(TClr.530
+ Red: 0xfa00
+ Green: 0xf800
+)
+
+(TClr.531
+ Red: 0xbf00
+ Green: 0xbf00
+)
+
+(TClr.532
+ Red: 0xc300
+ Green: 0x9a00
+ Blue: 0x9f00
+)
+
+(TClr.533
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.534
+ Red: 0x700
+ Green: 0x8400
+ Blue: 0x2e00
+)
+
+(TClr.535
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.536
+ Green: 0xfc00
+ Blue: 0x600
+)
+
+(TClr.537
+ Green: 0xbf00
+ Blue: 0x4000
+)
+
+(TClr.538
+ Red: 0xa00
+ Green: 0x6400
+)
+
+(TClr.539
+ Green: 0x4000
+)
+
+(TClr.540
+ Red: 0x4b00
+ Green: 0x2e00
+ Blue: 0x6900
+)
+
+(TClr.541
+ Red: 0x800
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.542
+ Red: 0xb00
+ Blue: 0x2e00
+)
+
+(TClr.543
+ Blue: 0x4000
+)
+
+(TClr.544
+ Red: 0x600
+ Green: 0xf900
+)
+
+(TClr.545
+ Red: 0x4000
+ Green: 0xbf00
+)
+
+(TClr.546
+ Red: 0xfa00
+ Blue: 0xf600
+)
+
+(TClr.547
+ Red: 0xbf00
+ Blue: 0xbf00
+)
+
+(TClr.548
+ Red: 0x9a00
+ Green: 0x2e00
+ Blue: 0x9d00
+)
+
+(TClr.549
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.550
+ Red: 0x6400
+ Green: 0x6400
+)
+
+(TClr.551
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.552
+ Red: 0x9f00
+ Green: 0x9e00
+ Blue: 0x600
+)
+
+(TClr.553
+ Red: 0x800
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.554
+ Red: 0xfc00
+ Blue: 0xf700
+)
+
+(TClr.555
+ Red: 0xbf00
+ Blue: 0xbf00
+)
+
+(TClr.556
+ Red: 0x600
+ Green: 0x3d00
+ Blue: 0xec00
+)
+
+(TClr.557
+ Red: 0x4000
+ Green: 0x800
+ Blue: 0x4000
+)
+
+(TClr.558
+ Green: 0x8400
+ Blue: 0xf800
+)
+
+(TClr.559
+ Green: 0x4000
+ Blue: 0xbf00
+)
+
+(TClr.560
+ Red: 0x4000
+ Green: 0xfc00
+)
+
+(TClr.561
+ Red: 0x800
+ Green: 0xbf00
+)
+
+(TClr.562
+ Red: 0xfa00
+ Green: 0x6400
+ Blue: 0xf700
+)
+
+(TClr.563
+ Red: 0xbf00
+ Green: 0x4000
+ Blue: 0xbf00
+)
+
+(TClr.564
+ Red: 0x5700
+ Green: 0x2e00
+ Blue: 0xec00
+)
+
+(TClr.565
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.566
+ Red: 0x4000
+ Blue: 0x2e00
+)
+
+(TClr.567
+ Red: 0x800
+ Blue: 0x4000
+)
+
+(TClr.568
+ Green: 0x4000
+ Blue: 0xf800
+)
+
+(TClr.569
+ Green: 0x800
+ Blue: 0xbf00
+)
+
+(TClr.570
+ Blue: 0x3c00
+)
+
+(TClr.571
+ Blue: 0x800
+)
+
+(TClr.572
+ Red: 0x5600
+ Green: 0x2e00
+ Blue: 0x9f00
+)
+
+(TClr.573
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.574
+ Red: 0x3900
+ Green: 0x6400
+)
+
+(TClr.575
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.576
+ Red: 0x9700
+ Green: 0x9e00
+)
+
+(TClr.577
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.578
+ Red: 0x4000
+ Blue: 0xf600
+)
+
+(TClr.579
+ Red: 0x800
+ Blue: 0xbf00
+)
+
+(TClr.580
+ Red: 0x600
+ Green: 0xb00
+ Blue: 0x9d00
+)
+
+(TClr.581
+ Red: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.582
+ Red: 0x6d00
+ Green: 0x8400
+)
+
+(TClr.583
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.584
+ Red: 0x3d00
+ Green: 0xfc00
+ Blue: 0x1d00
+)
+
+(TClr.585
+ Red: 0x4000
+ Green: 0xbf00
+ Blue: 0x800
+)
+
+(TClr.586
+ Red: 0xfa00
+ Green: 0x6400
+ Blue: 0xf600
+)
+
+(TClr.587
+ Red: 0xbf00
+ Green: 0x4000
+ Blue: 0xbf00
+)
+
+(TClr.588
+ Red: 0x6c00
+ Green: 0x2e00
+ Blue: 0x900
+)
+
+(TClr.589
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x6500
+)
+
+(TClr.590
+ Red: 0x4000
+ Blue: 0x1d00
+)
+
+(TClr.591
+ Red: 0x800
+ Blue: 0x800
+)
+
+(TClr.592
+ Green: 0x4000
+ Blue: 0x1d00
+)
+
+(TClr.593
+ Green: 0x800
+ Blue: 0x800
+)
+
+(TClr.594
+)
+
+(TClr.595
+)
+
+(TClr.596
+ Red: 0x6c00
+ Green: 0xb300
+)
+
+(TClr.597
+ Red: 0x4000
+ Green: 0x4000
+)
+
+(TClr.598
+ Red: 0x3900
+ Green: 0xf900
+ Blue: 0xff00
+)
+
+(TClr.599
+ Red: 0x4000
+ Green: 0xbf00
+ Blue: 0x7f00
+)
+
+(TClr.600
+ Red: 0x9700
+ Green: 0x6f00
+ Blue: 0x600
+)
+
+(TClr.601
+ Red: 0x4000
+ Green: 0x4000
+ Blue: 0x4000
+)
+
+(TClr.602
+ Red: 0xe400
+ Green: 0xb200
+)
+
+(TClr.603
+ Red: 0x800
+ Green: 0x4000
+)
+
+(TClr.604
+ Red: 0x4000
+ Green: 0x8a00
+)
+
+(TClr.605
+ Red: 0x800
+ Green: 0x4000
+)
+
+(TClr.606
+)
+
+(TClr.607
+)
+
+(TClr.608
+)
+
+(Thresh.609
+)
+
+(GSet.610
+)
+
+(LButn.611
+ HelpTopic: "New_button"
+ Update: "Doc.NewUpdate"
+ Label: "&Neu"
+ Click: "View.New"
+)
+
+(LButn.612
+ HelpTopic: "Open_button"
+ Update: "Doc.OpenUpdate"
+ Label: "Öffn&en"
+ Click: "Doc.Open"
+)
+
+(LButn.613
+ HelpTopic: "Print_button"
+ Update: "Doc.ActionUpdate"
+ Label: "D&rucken"
+ Click: "Doc.Action"
+)
+
+(NameDict.614
+)
+
+(NameDict.615
+ Obj: 616
+ Obj: 617
+)
+
+(AVDict.616
+ InternalName: "Table of Contents Defaults Dialog"
+)
+
+(AVDict.617
+ InternalName: "_Thor_"
+)
+
+(FN.1461
+ Path: "$HOME"
+)
+
+(TClr.1462
+ Red: 0xffff
+ Green: 0xffff
+)
+
+(AVStr.1463
+ S: "View"
+)
+
+(AVStr.1464
+ S: "Table"
+)
+
+(AVStr.1465
+ S: "Chart"
+)
+
+(AVStr.1466
+ S: "Layout"
+)
+
+(AVStr.1467
+ S: "Script"
+)
+
+(AVStr.1468
+ S: "Project"
+)
+
+(AVStr.1469
+ S: "Appl"
+)
+
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/test/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/test/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/test/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+This directory contains tests of the importAPR extension.
+
+Howto run test (assume thuban source is under ~/project):
+
+export PYTHONPATH=~/project/thuban:~/project/thuban/Lib:~/project/thuban/test
+python test_apr.py
Added: packages/thuban/branches/upstream/current/Extensions/importAPR/test/test_apr.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/importAPR/test/test_apr.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/importAPR/test/test_apr.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,108 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Tests for APR classes.
+"""
+
+__version__ = "$Revision: 1732 $"
+# $Source$
+# $Id: test_apr.py 1732 2003-09-22 12:22:16Z jan $
+
+import unittest
+
+from Thuban.Model.color import Color, Transparent
+from Thuban.Model.range import Range
+
+from Extensions.importAPR.apr import APR_LClass, APR_TClr
+from Extensions.importAPR.importAPR import ODB
+
+class aprTest(unittest.TestCase):
+
+ def test_TClr(self):
+ """Test the APR_TClr class."""
+ eq = self.assertEquals
+
+ # list with tupels (TClr object, Color object to test against)
+ lst = []
+
+ # a standard RGB TClr object (here: white)
+ obj = APR_TClr(None, 'TClr', 1)
+ setattr(obj, 'Red', '0xffff')
+ setattr(obj, 'Green', '0xffff')
+ setattr(obj, 'Blue', '0xffff')
+ lst.append( (obj, Color(1,1,1)) )
+
+ # an empty TClr object
+ obj = APR_TClr(None, 'TClr', 2)
+ lst.append( (obj, Color(0,0,0)) )
+
+ # an incomplete RGB TClr object (here: only red)
+ obj = APR_TClr(None, 'TClr', 3)
+ setattr(obj, 'Red', '0xffff')
+ lst.append( (obj, Color(1,0,0)) )
+
+ # an incomplete RGB TClr object (here: no full 4 digits of hex-code)
+ obj = APR_TClr(None, 'TClr', 4)
+ setattr(obj, 'Green', '0x0f')
+ obj2 = APR_TClr(None, 'TClr', 5)
+ setattr(obj2, 'Green', '0x0f00')
+ lst.append( (obj, obj2.GetThubanColor()) )
+
+ # a transparent TClr object
+ obj = APR_TClr(None, 'TClr', 6)
+ setattr(obj, 'Name', 'Transparent')
+ lst.append( (obj, Transparent) )
+
+ # finally test all the colors
+ for tclr, color in lst:
+ eq(tclr.GetThubanColor(), color)
+
+ def test_LClass(self):
+ """Test the APR_LClass class."""
+ eq = self.assertEquals
+
+ # list with tupels (TClr object, Color object to test against)
+ lst = []
+
+ # a standard LClass object with numerical range
+ obj = APR_LClass(None, 'LClass', 1)
+ setattr(obj, 'MinNum', '4.00000000000000')
+ setattr(obj, 'MaxNum', '8.00000000000000')
+ setattr(obj, 'Precision', '-3')
+ setattr(obj, 'Label', '3')
+ eq(obj.GetLabel(), '3') # label OK?
+ eq(obj.GetThubanRange().__str__(), Range(']4;8]').__str__()) # range OK?
+
+ # a LClass object with half of the numerical range
+ obj = APR_LClass(None, 'LClass', 1)
+ setattr(obj, 'MaxNum', '8.00000000000000')
+ setattr(obj, 'Precision', '-3')
+ setattr(obj, 'Label', '3')
+ eq(obj.GetLabel(), '3') # label OK?
+ eq(obj.GetThubanRange(), Range(']-oo;8]')) # range OK?
+
+ # a LClass object with a string range describing a single value
+ obj = APR_LClass(None, 'LClass', 1)
+ setattr(obj, 'IsText', '1')
+ setattr(obj, 'MinStr', 'BUILDING')
+ setattr(obj, 'MaxStr', 'BUILDING')
+ setattr(obj, 'Precision', '-3')
+ setattr(obj, 'Label', 'BUILDING')
+ eq(obj.GetLabel(), 'BUILDING') # label OK?
+ eq(obj.GetThubanRange(), 'BUILDING') # range OK?
+
+ # a LClass text object without minstr/maxstr/label
+ obj = APR_LClass(None, 'LClass', 1)
+ setattr(obj, 'IsText', '1')
+ setattr(obj, 'Precision', '-3')
+ eq(obj.GetLabel(), '') # label OK?
+ eq(obj.GetThubanRange(), '') # range OK?
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/Extensions/mouseposition/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/mouseposition/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/mouseposition/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,21 @@
+# Copyright (C) 2005 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank at intevation.de> (2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# import the actual module
+import mouseposition
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'mouseposition',
+ version = '1.0.0',
+ authors= [ 'Frank Koormann' ],
+ copyright = '2005 Intevation GmbH',
+ desc = _("On mouse click display the current coordinates\n" \
+ "in a dialog for easy further processing.")))
Added: packages/thuban/branches/upstream/current/Extensions/mouseposition/mouseposition.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/mouseposition/mouseposition.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/mouseposition/mouseposition.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,119 @@
+# Copyright (C) 2005 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank at intevation.de> (2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+xtend thuban with a locator tool.
+
+Collect positions of mouse clicks (in map coordinates) in a text control.
+
+The tool was implemented in the need to collect some coordinates for some
+work (outside Thuban). The status bar display of the coordinates is quite
+transient (each mouse movement changes it) and cannot be copied. The tool let
+one simply collect the coordinates needed and copy them in one block later.
+"""
+
+__version__ = '$Revision: 2721 $'
+# $Source$
+# $Id: mouseposition.py 2721 2007-01-13 15:11:42Z dpinte $
+
+import os, sys
+import string
+
+import wx
+from wx.lib.layoutf import Layoutf
+
+from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+from Thuban.UI.command import registry, ToolCommand
+from Thuban.UI.mainwindow import main_menu, main_toolbar, \
+ make_check_current_tool
+from Thuban.UI.viewport import Tool
+from Thuban.UI.dialogs import NonModalDialog
+from Thuban import _
+
+import Thuban
+
+class DynamicMessageDialog(NonModalDialog):
+ """Similar to the wx.ScrolledMessageDialog, contents dynamically
+ changeable by calling applications.
+
+ """
+ def __init__(self, parent, msg, name, caption, pos = wx.DefaultPosition):
+ NonModalDialog.__init__(self, parent, name, caption)
+ x, y = pos
+ if x == -1 and y == -1:
+ self.CenterOnScreen(wx.BOTH)
+ text = wx.TextCtrl(self, -1, msg, wx.DefaultPosition,
+ wx.DefaultSize,
+ wx.TE_MULTILINE | wx.TE_READONLY)
+ ok = wx.Button(self, wx.ID_OK, "OK")
+ text.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)))
+ ok.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,)))
+ wx.EVT_BUTTON(self, wx.ID_OK, self.OnClose)
+ self.text = text
+ self.SetAutoLayout(1)
+ self.Layout()
+
+ def getText(self):
+ return self.text.GetValue()
+
+ def setText(self, text):
+ self.text.SetValue(text)
+
+ def appendText(self, text):
+ self.text.AppendText(text)
+
+class MousePositionTool(Tool):
+
+ def __init__(self, view, context):
+ Tool.__init__(self, view)
+ self.context = context
+ self.dlg = None
+
+ def Name(self):
+ return "MousePositionTool"
+
+ def MouseDown(self, event):
+ map_proj = self.view.Map().GetProjection()
+ pos = self.view.CurrentPosition()
+ if pos is not None:
+ pMsg = "%10.10g, %10.10g\n" % pos
+ name = "extension_mouse_position"
+
+ dialog = self.context.mainwindow.get_open_dialog(name)
+ if dialog is None:
+ dialog = DynamicMessageDialog(self.context.mainwindow,
+ pMsg, name, _("Mouse Position Tool"))
+ self.context.mainwindow.add_dialog(name, dialog)
+ dialog.Show(True)
+ else:
+ dialog.appendText(pMsg)
+ dialog.Raise()
+
+def mouse_position_tool(context):
+ canvas = context.mainwindow.canvas
+ canvas.SelectTool(MousePositionTool(canvas, context))
+
+
+# locator executed as an tool/extension to Thuban
+iconfile = os.path.join(os.path.abspath(Thuban.__path__[0]),
+ "..", "Resources", "Bitmaps", "identify")
+iconfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'position')
+registry.Add(ToolCommand("mouse_position_tool", "Mouse Position Tool",
+ mouse_position_tool, icon = iconfile,
+ helptext = "Collect mouse click coordinates in a dialog",
+ checked = make_check_current_tool("MousePositionTool")))
+
+# Add the command to the toolbar
+main_toolbar.InsertSeparator()
+main_toolbar.InsertItem("mouse_position_tool")
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally add the new entry to the extensions menu
+extensions_menu.InsertItem('mouse_position_tool')
Added: packages/thuban/branches/upstream/current/Extensions/mouseposition/position.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/mouseposition/position.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/mouseposition/position.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * position_xpm[] = {
+"24 24 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ",
+" . ",
+" . .... ",
+" .+ .+... .. ",
+" .. .+......... ",
+" ..+ .+........... ",
+" ... ..+...........+ ",
+" ...+ .+............+ ",
+" .... .............++ ",
+" ....+.+ ..........+ ",
+" ......+ +.......++ ",
+" .....++ ++....+ ",
+" ......+ ++++ ",
+" ......+ ",
+" ....... ",
+" ...+...+ ",
+" ..++.... ",
+" .++.+++.+ ",
+" + .+ ++ ",
+" .+ ",
+" .+ ",
+" + ",
+" "};
Added: packages/thuban/branches/upstream/current/Extensions/ogr/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,36 @@
+# Copyright (C) 2004 by Intevation GmbH vim:encoding=latin-1:
+# Authors:
+# Nina Hüffmeyer <nhueffme at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+__version__ = "$Revision: 2713 $"
+# $Source$
+# $Id: __init__.py 2713 2006-10-26 16:37:42Z bernhard $
+
+# import the actual modules
+from os import environ
+from sys import platform
+
+try:
+ if platform != 'win32':
+ dummy = environ['DISPLAY']
+ import ogrstart
+except KeyError:
+ pass # For non-win32 platform, we don't have a DISPLAY, so don't import
+ # the modules (for test mode)
+ # For win32 platform, there is always have a graphical mode
+ # Not sure whether this is the best method to avoid problems
+ # in the global test routine.
+
+# perform the registration of the extension
+from Thuban import _, internal_from_unicode
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'OGRstart',
+ version = '0.9.0',
+ authors= [ internal_from_unicode(u'Nina H\xfcffmeyer') ],
+ copyright = '2004 Intevation GmbH',
+ desc = _("Open a file supported by ogr.")))
Added: packages/thuban/branches/upstream/current/Extensions/ogr/ogrdialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/ogrdialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/ogrdialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,416 @@
+# Copyright (c) 2001, 2003, 2004 by Intevation GmbH vim:encoding=latin-1:
+# Authors:
+# Martin Müller <mmueller at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""Dialogs to manage database connections"""
+
+import sys, traceback
+
+import wx
+
+try:
+ import ogr
+except ImportError:
+ ogr = None
+
+from Thuban import _
+from Thuban.Model.table import FIELDTYPE_INT
+from Extensions.ogr import ogrshapes
+
+
+ID_DBCHOOSE_RETRIEVE = 9201
+ID_DBCHOOSE_OK = 9202
+ID_DBCHOOSE_CANCEL = 9203
+ID_LB_DCLICK = 9204
+
+
+class ChooseFileFormat(wx.Dialog):
+ """This dialog lists all available drivers.
+ """
+ def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
+ wx.Dialog.__init__(self, parent, -1, _("Choose file format"),
+ style = wx.DIALOG_MODAL|wx.CAPTION)
+ self.session = session
+ self.tables = []
+
+ #
+ # Build the dialog
+ #
+
+ # Sizer for the entire dialog
+ top = wx.FlexGridSizer(2, 1, 0, 0)
+
+ # Sizer for the main part with the list box
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ top.Add(main_sizer, 1, wx.EXPAND, 0)
+
+ # The list box with the drivers
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, "File formats"),
+ wx.HORIZONTAL)
+ self.lb_drivers = wx.ListBox(self, -1)
+ static_box.Add(self.lb_drivers, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ for i in range(ogr.GetDriverCount()):
+ self.lb_drivers.Append(ogr.GetDriver(i).GetName())
+ if self.lb_drivers.GetCount() > 0:
+ self.lb_drivers.SetSelection(0, True)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wx.FlexGridSizer(1, 2, 0, 0)
+ ok_button = wx.Button(self, ID_DBCHOOSE_OK, _("OK"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+ buttons.Add(ok_button, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ cancel_button = wx.Button(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+ buttons.Add(cancel_button, 0, wx.ALL, 4)
+ top.Add(buttons, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+
+ def GetTable(self):
+ """no functionality
+ """
+ return None
+
+ def OnLBDClick(self, event):
+ """Close dialog.
+ """
+ if self.lb_tables.GetSelection() >= 0:
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnOK(self, event):
+ """Close dialog.
+ """
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnCancel(self, event):
+ """Close dialog.
+ """
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+
+class ChooseLayer(wx.Dialog):
+ """This dialog lists all the layers contained in the given datasource.
+
+ One layer can be chosen, which is then opened.
+ """
+
+ def __init__(self, parent, filename):
+ """Initialize the dialog.
+ """
+ wx.Dialog.__init__(self, parent, -1, _("Choose layer"),
+ style = wx.DIALOG_MODAL|wx.CAPTION)
+ self.tables = []
+
+ #
+ # Build the dialog
+ #
+
+ # Sizer for the entire dialog
+ top = wx.FlexGridSizer(2, 1, 0, 0)
+
+ # Sizer for the main part with the list boxes
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ top.Add(main_sizer, 1, wx.EXPAND, 0)
+
+ # The list box with the drivers
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, _("Layers")),
+ wx.HORIZONTAL)
+ self.lb_drivers = wx.ListBox(self, -1)
+ static_box.Add(self.lb_drivers, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ datasource = ogr.Open(filename)
+ self.layer = []
+ for i in range(datasource.GetLayerCount()):
+ self.layer.append(datasource.GetLayer(i))
+ self.lb_drivers.Append(datasource.GetLayer(i).GetName())
+ if self.lb_drivers.GetCount() > 0:
+ self.lb_drivers.SetSelection(0, True)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wx.FlexGridSizer(1, 2, 0, 0)
+ ok_button = wx.Button(self, ID_DBCHOOSE_OK, _("OK"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+ buttons.Add(ok_button, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ cancel_button = wx.Button(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+ buttons.Add(cancel_button, 0, wx.ALL, 4)
+ top.Add(buttons, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+ def end_dialog(self, result):
+ """If the dialog is closed with OK, set chosen layer as layer
+ to be opened.
+ """
+ self.result = result
+ if result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ """Dialog closed with OK button.
+ """
+ self.end_dialog(self.lb_drivers.GetSelection())
+
+ def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
+ self.end_dialog(None)
+
+ def GetLayer(self):
+ """Return the selected layer."""
+ return self.layer[self.lb_drivers.GetSelection()].GetName()
+
+
+class ChooseOGRDBTableDialog(wx.Dialog):
+ """This dialog opens a datasource from an existing database connection.
+
+ A list of all available database connections is offered. If one connection
+ is selected and the button "Retrieve" is clicked, all layers are listed.
+ One of these layers can be chosen to be opened.
+ An ID column can be chosen, too."""
+
+ def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
+ wx.Dialog.__init__(self, parent, -1, _("Choose layer from database"),
+ style = wx.DIALOG_MODAL|wx.CAPTION)
+ self.session = session
+ self.dbconns = self.session.DBConnections()
+ self.tables = []
+
+ #
+ # Build the dialog
+ #
+
+ # Sizer for the entire dialog
+ top = wx.FlexGridSizer(2, 1, 0, 0)
+
+ # Sizer for the main part with the list boxes
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ top.Add(main_sizer, 1, wx.EXPAND, 0)
+
+ # The list box with the connections
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, _("Databases")),
+ wx.HORIZONTAL)
+ self.lb_connections = wx.ListBox(self, -1)
+ static_box.Add(self.lb_connections, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ for i in range(len(self.dbconns)):
+ self.lb_connections.Append(self.dbconns[i].BriefDescription())
+ if self.lb_connections.GetCount() > 0:
+ self.lb_connections.SetSelection(0, True)
+
+ # The button box between the connections list box and the table
+ # list box
+ buttons = wx.FlexGridSizer(3, 1, 0, 0)
+ buttons.Add(20, 80, 0, wx.EXPAND, 0)
+ retrieve_button = wx.Button(self, ID_DBCHOOSE_RETRIEVE, _("Retrieve"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_RETRIEVE, self.OnRetrieve)
+ buttons.Add(retrieve_button, 0, wx.ALL
+ |wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 4)
+ buttons.Add(20, 80, 0, wx.EXPAND, 0)
+ main_sizer.Add(buttons, 0, wx.EXPAND, 0)
+
+ # The list box with the tables
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, _("Tables")),
+ wx.HORIZONTAL)
+ self.lb_tables = wx.ListBox(self, ID_LB_DCLICK)
+ wx.EVT_LISTBOX(self, ID_LB_DCLICK, self.OnTableSelect)
+ wx.EVT_LISTBOX_DCLICK(self, ID_LB_DCLICK, self.OnLBDClick)
+ static_box.Add(self.lb_tables, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ # id column and geometry column selection
+ box = wx.BoxSizer(wx.VERTICAL)
+ box.Add(wx.StaticText(self, -1, _("ID Column")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_id_column = wx.ComboBox(self, -1, "")
+ box.Add(self.text_id_column, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ main_sizer.Add(box, 1, wx.EXPAND, 0)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wx.FlexGridSizer(1, 2, 0, 0)
+ ok_button = wx.Button(self, ID_DBCHOOSE_OK, _("OK"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+ buttons.Add(ok_button, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ cancel_button = wx.Button(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+ buttons.Add(cancel_button, 0, wx.ALL, 4)
+ top.Add(buttons, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+
+ def GetTable(self):
+ """Return the chosen DB connection, the table to be opened,
+ the connection string for ogr and the ID column.
+ """
+ i = self.lb_tables.GetSelection()
+ if i >= 0:
+ return (self.selected_conn, self.connString, self.tables[i],
+ self.text_id_column.GetValue())
+ return None
+
+ def OnRetrieve(self, event):
+ """Provide a list of all available layers in the selected datasource.
+ """
+ i = self.lb_connections.GetSelection()
+ if i >= 0:
+ self.selected_conn = self.dbconns[i]
+ self.connString = "PG: dbname=%s" %self.selected_conn.dbname
+ if self.selected_conn.host is not "":
+ self.connString = (self.connString + " host=%s"
+ %self.selected_conn.host)
+ if self.selected_conn.user is not "":
+ self.connString = (self.connString + " user=%s"
+ %self.selected_conn.user)
+ if self.selected_conn.password is not "":
+ self.connString = (self.connString + " password=%s"
+ %self.selected_conn.password)
+ if self.selected_conn.port is not "":
+ self.connString = (self.connString + " port= %s"
+ %self.selected_conn.port)
+ ds = ogr.Open(self.connString)
+ if ds:
+ for i in range(ds.GetLayerCount()):
+ self.tables.append(ds.GetLayer(i).GetName())
+ self.lb_tables.Set(self.tables)
+
+ def OnTableSelect(self, event):
+ """If a table is selected, list all possible ID columns.
+ """
+ i = self.lb_tables.GetSelection()
+ self.text_id_column.Clear()
+ if i >= 0:
+ for name, typ in self.selected_conn.table_columns(self.tables[i]):
+ if typ == FIELDTYPE_INT:
+ self.text_id_column.Append(name)
+
+ def OnLBDClick(self, event):
+ """Close dialog.
+ """
+ if self.lb_tables.GetSelection() >= 0:
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnOK(self, event):
+ """Dialog closed with OK button.
+ """
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+
+class OGRConnectionDialog(wx.Dialog):
+ """A string can be enteres, which is directly passed to ogr to open a
+ datasource.
+ """
+ def __init__(self, parent, session):
+ """Initialize the dialog.
+ """
+ wx.Dialog.__init__(self, parent, -1, "Enter string for OGRConnection",
+ style = wx.DIALOG_MODAL|wx.CAPTION)
+ self.session = session
+
+ # Sizer for the entire dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+
+ # The list box with the drivers
+ box = wx.BoxSizer(wx.HORIZONTAL)#wx.Box(self, -1, _("OGRConnection")),
+ # wx.HORIZONTAL)
+ box.Add(wx.StaticText(self, -1, _("URL:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_string = wx.TextCtrl(self, -1, "")
+ box.Add(self.text_string, 0, wx.EXPAND, 0)
+ top.Add(box, 0, wx.EXPAND)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wx.FlexGridSizer(1, 2, 0, 0)
+ ok_button = wx.Button(self, ID_DBCHOOSE_OK, _("OK"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_OK, self.OnOK)
+ buttons.Add(ok_button, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ cancel_button = wx.Button(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ wx.EVT_BUTTON(self, ID_DBCHOOSE_CANCEL, self.OnCancel)
+ buttons.Add(cancel_button, 0, wx.ALL, 4)
+ top.Add(buttons, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+ def RunDialog(self):
+ """Run dialog
+ """
+ self.ShowModal()
+ self.Destroy()
+ return self.result
+
+ def end_dialog(self, result):
+ """Close dialog
+ """
+ self.result = result
+ if result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ """Dialog closed with OK
+ """
+ result = {}
+ result["string"] = getattr(self, "text_string").GetValue()
+ self.end_dialog(result)
+
+ def OnCancel(self, event):
+ """Dialog closed with Cancel.
+ """
+ self.end_dialog(None)
+
+ def GetDatasourceName(self):
+ """Return the string to be used for opening the database
+ """
+ return self.result["string"]
+
Added: packages/thuban/branches/upstream/current/Extensions/ogr/ogrshapes.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/ogrshapes.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/ogrshapes.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,853 @@
+# Copyright (C) 2004 by Intevation GmbH vim:encoding=latin-1:
+# Authors:
+# Nina Hüffmeyer <nhueffme at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+__version__ = "$Revision: 2713 $"
+# $Source$
+# $Id: ogrshapes.py 2713 2006-10-26 16:37:42Z bernhard $
+
+from __future__ import generators
+
+try:
+ import ogr
+except ImportError:
+ ogr = None
+
+import os
+
+from Thuban import _
+from Thuban.Model import table
+from Thuban.Model import transientdb
+from Thuban.Model.transientdb import TransientDatabase
+
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
+from Thuban.Model.data import RAW_PYTHON, RAW_SHAPEFILE, RAW_WKT
+from Thuban.Model.data import FileShapeStore
+
+def has_ogr_support():
+ """Return whether this Thuban instance supports ogr file formats
+
+ Having OGR support means that the ogr module can be
+ imported.
+ """
+ return ogr is not None
+
+if ogr is not None:
+ SHAPETYPE_UNKNOWN = ogr.wkbUnknown
+ SHAPETYPE_GEOMCOLL = ogr.wkbGeometryCollection
+ SHAPETYPE_NONE = ogr.wkbNone
+
+ # mapping from ogr-lib shapetypes and table constants to our constants
+ ogrlib_shapetypes = {ogr.wkbPolygon: SHAPETYPE_POLYGON,
+ ogr.wkbLineString: SHAPETYPE_ARC,
+ ogr.wkbPoint: SHAPETYPE_POINT,
+ ogr.wkbUnknown: SHAPETYPE_UNKNOWN,
+ ogr.wkbNone: SHAPETYPE_NONE,
+ ogr.wkbGeometryCollection: SHAPETYPE_GEOMCOLL}
+
+ fieldtype_map = {ogr.OFTString: table.FIELDTYPE_STRING,
+ ogr.OFTInteger: table.FIELDTYPE_INT,
+ ogr.OFTReal: table.FIELDTYPE_DOUBLE}
+
+else:
+ ogrlib_shapetypes = {}
+ fieldtype_map = {}
+ SHAPETYPE_UNKNOWN = 0
+ SHAPETYPE_GEOMCOLL = 7
+ SHAPETYPE_NONE = 100
+
+
+class OGRShape:
+ """Represent one shape of an OGRShapeStore
+ """
+
+ def __init__(self, shapestore, shape):
+ """Initialize the shape object.
+
+ shapestore should be an instance of OGRShapeStore,
+ shape should be an instance of an OGRFeature.
+ """
+ self.ogrlayer = shapestore.ogrlayer
+ id_column = shapestore.Id_column()
+ self.feature = shape
+ if id_column is None:
+ self.shapeid = self.feature.GetFID()
+ else:
+ self.shapeid = self.feature.GetField(id_column)
+ self.geom = self.feature.GetGeometryRef()
+ if self.geom:
+ self.shapetype = self.geom.GetGeometryType()
+ self.bbox = self._compute_bbox()
+ self.points = self._points()
+ else:
+ self.shapetype = ogr.wkbNone
+ self.bbox = None
+ self.points = [[]]
+ try:
+ self.shapetype = ogrlib_shapetypes[self.shapetype]
+ except:
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+ self.geoms = self._geoms()
+
+ def _geoms(self):
+ """Return a list of geometry objects.
+
+ If the shape is a geometry collection, all contained geometry
+ objects are stored to the list as OGRGeometry objects.
+ """
+ geoms = []
+ if self.shapetype == SHAPETYPE_GEOMCOLL:
+ for i in range(self.geom.GetGeometryCount()):
+ geoms.append(OGRGeometry(self, self.geom, i))
+ return geoms
+
+ def _compute_bbox(self):
+ """
+ Compute the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ """
+ minx, maxx, miny, maxy = self.geom.GetEnvelope()
+ return (minx, miny, maxx, maxy)
+
+ def compute_bbox(self):
+ """
+ Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ """
+ return self.bbox
+
+ def ShapeID(self):
+ """Return the feature id of this shape.
+ """
+ return self.shapeid
+
+ def Points(self):
+ """Return the coordinates of the shape as a list of lists of pairs
+ """
+ return self.points
+
+ def _points(self):
+ """Get the coordinates of the shape as a list of lists of pairs
+ """
+ shape = []
+
+ if self.geom is None:
+ return shape.append([])
+
+ # if geometry object is of type point or line
+ if self.geom.GetGeometryCount() == 0:
+ points =[]
+ for point in range(self.geom.GetPointCount()):
+ x = self.geom.GetX(point)
+ y = self.geom.GetY(point)
+ points.append((x, y))
+ return [points]
+ # if geometry object is of type polygon or multipolygon
+ for i in range(self.geom.GetGeometryCount()):
+ points = []
+ geometry = self.geom.GetGeometryRef(i)
+ # if geometry object is polygon
+ if geometry.GetGeometryCount() == 0:
+ for point in range(geometry.GetPointCount()):
+ x = geometry.GetX(point)
+ y = geometry.GetY(point)
+ points.append((x, y))
+ shape.append(points)
+ # if geometry object is of type multipolygon or geometry collection
+ else:
+ for j in range(geometry.GetGeometryCount()):
+ points = []
+ subgeom = geometry.GetGeometryRef(j)
+ for point in range(subgeom.GetPointCount()):
+ x = subgeom.GetX(point)
+ y = subgeom.GetY(point)
+ points.append((x, y))
+ shape.append(points)
+ return shape
+
+ def RawData(self):
+ """Return the shape id to use with the shapestore
+ """
+ return self.shapeid
+
+ def OGRLayer(self):
+ """Return the ogrlayer object
+ """
+ return self.ogrlayer
+
+ def ShapeType(self):
+ """Return the shapetype of this shape (may differ from the layer's
+ shapetype)
+ """
+ return self.shapetype
+
+ def GetGeoms(self):
+ """Return the list of geometries of this feature.
+
+ If this feature is a geometry collection, all contained geometries
+ are given. Else the returned list is empty.
+ """
+ return self.geoms
+
+ def GetGeom(self, index):
+ """Return the OGRGeometry object at the specified index.
+
+ This is not none only if the shape is a geometry collection.
+ """
+ if index < len(self.geoms):
+ return self.geoms[index]
+ else:
+ return None
+
+
+class OGRGeometry:
+ """This class represents a geometry belonging to a specified feature.
+ """
+
+ def __init__(self, shape, geom, index):
+ """Initialize the geometry object.
+
+ shape should be an OGRShape, which this geometry belongs to.
+ geom is the base geometry, index is the ReferenceID.
+ """
+ self.shape = shape
+ self.index = index
+
+ self.geom = geom.GetGeometryRef(index)
+ try:
+ self.shapetype = ogrlib_shapetypes[self.geom.GetGeometryType()]
+ except:
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+
+ def ShapeType(self):
+ """Return the shapetype of this geometry object."""
+ return self.shapetype
+
+
+class OGRShapeStore:
+ """Corresponds to an OGRLayer object, containing features/shapes and
+ providing the same methods like ShapefileStore.
+
+ In fact, for all file based shape stores, the class OGRFileShapeStore
+ should be used. Only database shape stores should be
+ used with OGRShapeStore. It is subject to re-factoring
+ to end up with better class names and sensible base classes.
+ """
+
+ # TODO: re-factor this class to be not responsible for file-based
+ # stores anymore.
+
+ def __init__(self, session, filename, layername, id_column = None):
+ """Initialize the shapestore.
+
+ All required information is loaded from the datasource.
+ """
+ # if id_column is None, data is loaded from file, so we need path
+ # if id_column is not None, data is loaded from database
+ if id_column is None:
+ self.filename = os.path.abspath(filename)
+ else:
+ self.filename = filename
+ self.layername = layername
+
+ self.ogrdatasource = ogr.Open(filename)
+ self.ogrlayer = (self.ogrdatasource).GetLayerByName(layername)
+
+ if id_column is not None:
+ self.id_column = id_column
+ else:
+ self.id_column = None
+
+ self.table = OGRTable(session, self.ogrdatasource, self.ogrlayer,
+ self.id_column)
+
+ self._open_ogrlayer(layername)
+
+ def _open_ogrlayer(self, layername):
+ """Get all required information from the datasource.
+ """
+ self.numshapes = self.ogrlayer.GetFeatureCount()
+ self.shapetype = self.ogrlayer.GetLayerDefn().GetGeomType()
+
+ extent = self.ogrlayer.GetExtent()
+ if extent:
+ self.bbox = [extent[0], extent[2], extent[1], extent[3]]
+ else:
+ self.bbox = None
+
+ try:
+ self.shapetype = ogrlib_shapetypes[self.shapetype]
+ except:
+ # if shapetype is not contained in ogrlib_shapetypes
+ # treat it like SHAPETYPE_UNKNOWN
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+ self.shapes = self.shapes()
+
+ def shapes(self):
+ """Return a collection of all features as OGRShape objects.
+ """
+ shapes = {}
+ self.ogrlayer.ResetReading()
+ if self.id_column is None:
+ nextFeature = self.ogrlayer.GetNextFeature()
+ while nextFeature is not None:
+ fid = nextFeature.GetFID()
+ shape = OGRShape(self, nextFeature)
+ shapes[shape.ShapeID()] = shape
+ nextFeature = self.ogrlayer.GetNextFeature()
+ else:
+ lay = self.ogrdatasource.ExecuteSQL("SELECT %s, * from %s"
+ % (self.id_column, self.layername))
+ if lay is not None:
+ lay.ResetReading()
+ nextFeature = lay.GetNextFeature()
+ while nextFeature is not None:
+ fid = nextFeature.GetField(0)
+ shape = OGRShape(self, nextFeature)
+ shapes[shape.ShapeID()] = shape
+ nextFeature = lay.GetNextFeature()
+ self.ogrdatasource.ReleaseResultSet(lay)
+ return shapes
+
+ def OGRLayer(self):
+ """Return the OGRLayer object
+ """
+ return self.ogrlayer
+
+ def FileName(self):
+ """Return the filename used to open the file
+ """
+ return self.filename
+
+ def FileType(self):
+ """Return the filetype. This is depending on the driver used to open
+ the file.
+ """
+ return self.ogrdatasource.GetDriver().GetName()
+
+ def ShapeType(self):
+ """Return the type of the shapes in the shapestore.
+
+ This is either SHAPETYPE_POINT, SHAPETYPE_ARC, SHAPETYPE_POLYGON,
+ SHAEPTYPE_GEOMCOLL, SHAPETYPE_NONE or SHAPETYPE_UNKNOWN.
+ """
+ return self.shapetype
+
+ def RawShapeFormat(self):
+ """Return the raw data format of the shape data, i.e. RAW_PYTHON
+ """
+ return RAW_PYTHON
+
+ def NumShapes(self):
+ """Return the number of shapes in the shape store
+ """
+ return self.numshapes
+
+ def BoundingBox(self):
+ """Return the bounding box of the shapes in the shapestore.
+ """
+ return self.bbox
+
+ def ShapesInRegion(self, bbox):
+ """Return an iterable over the shapes that overlap the bounding box.
+
+ The bbox parameter should be the bounding box as a tuple in the
+ form (minx, miny, maxx, maxy) in the coordinate system of the
+ shape store.
+ """
+ left, bottom, right, top = bbox
+
+ # create a geometry which can be passed to the layer as spatial filter
+ bboxpolygon = ogr.CreateGeometryFromWkt(
+ ('Polygon((%s %s, %s %s, %s %s,%s %s, %s %s))'
+ %(left, bottom, left, top, right, top,
+ right, bottom, left, bottom)))
+
+ if self.ogrlayer.GetSpatialRef():
+ bboxpolygon.AssignSpatialReference(self.ogrlayer.GetSpatialRef())
+
+ self.ogrlayer.ResetReading()
+ #ogrlayer.SetSpatialFilterRect(left, bottom, right, top)
+ self.ogrlayer.SetSpatialFilter(bboxpolygon)
+
+ numFeatures = self.ogrlayer.GetFeatureCount()
+ # if no features are in bbox, return all features as shapesInRegion
+ # (PostGIS sometimes returns no features even if they are within
+ # the bounding box)
+ if numFeatures == 0:
+ self.ogrlayer.SetSpatialFilter(None)
+ numFeatures = self.ogrlayer.GetFeatureCount()
+ for feature in range(numFeatures):
+ nextFeature = self.ogrlayer.GetNextFeature()
+ if self.id_column is None:
+ yield self.shapes[nextFeature.GetFID()]
+ else:
+ yield self.shapes[nextFeature.GetField(self.id_column)]
+
+ self.ogrlayer.SetSpatialFilter(None)
+ bboxpolygon.Destroy()
+
+ def AllShapes(self):
+ """Return an iterable over the shapes in the shape store.
+ """
+ for id in range(len(self.shapes)):
+ yield self.shapes[id]
+
+ def Shape(self, fid):
+ """Return the shape with fid = fid
+ """
+ if fid in self.table.ids.keys():
+ return self.shapes[fid]
+ else:
+ return None
+
+ def Table(self):
+ """Return the table containing the attribute data
+ """
+ return self.table
+
+ def Dependencies(self):
+ """Return the empty tuple.
+ """
+ return ()
+
+ def OrigShapeStore(self):
+ """Return None."""
+ return None
+
+ def Id_column(self):
+ """Return the id_column.
+ """
+ return self.id_column
+
+class OGRFileShapeStore(FileShapeStore):
+ """Corresponds to an OGRLayer object, containing features/shapes and
+ providing the same methods like ShapefileStore.
+ """
+
+ def __init__(self, session, filename, layername, id_column = None):
+ """Initialize the shapestore.
+
+ All required information is loaded from the datasource.
+ """
+ self._bbox = None
+ self.ogrdatasource = ogr.Open(filename)
+
+ # filetype is depending on the driver used to open the file.
+ self._filetype = self.ogrdatasource.GetDriver().GetName()
+ if self._filetype == 'ESRI Shapefile':
+ self._filetype = "shapefile"
+ FileShapeStore.__init__(self, filename,
+ sublayer_name = layername)
+
+ self.ogrlayer = (self.ogrdatasource).GetLayerByName(layername)
+
+ self._table = OGRTable(session, self.ogrdatasource, self.ogrlayer,
+ id_column)
+
+ self._open_ogrlayer(layername)
+
+ def _open_ogrlayer(self, layername):
+ """Get all required information from the datasource.
+ """
+ self.numshapes = self.ogrlayer.GetFeatureCount()
+ self.shapetype = self.ogrlayer.GetLayerDefn().GetGeomType()
+
+ extent = self.ogrlayer.GetExtent()
+ if extent:
+ self._bbox = [extent[0], extent[2], extent[1], extent[3]]
+ else:
+ self._bbox = None
+
+ try:
+ self.shapetype = ogrlib_shapetypes[self.shapetype]
+ except:
+ # if shapetype is not contained in ogrlib_shapetypes
+ # treat it like SHAPETYPE_UNKNOWN
+ self.shapetype = ogrlib_shapetypes[ogr.wkbUnknown]
+
+ self.shapes = self.shapes()
+
+ def FileType(self):
+ """Return the filetype."""
+ return self._filetype
+
+ def BoundingBox(self):
+ """Return the bounding box of the shapes in the shape file.
+
+ The coordinate system used is whatever was used in the shape file.
+ If the shape file is empty, return None.
+ """
+ return self._bbox
+
+ def shapes(self):
+ """Return a collection of all features as OGRShape objects.
+ """
+ shapes = {}
+ self.ogrlayer.ResetReading()
+
+ nextFeature = self.ogrlayer.GetNextFeature()
+ while nextFeature is not None:
+ fid = nextFeature.GetFID()
+ shape = OGRShape(self, nextFeature)
+ shapes[shape.ShapeID()] = shape
+ nextFeature = self.ogrlayer.GetNextFeature()
+
+ return shapes
+
+ def OGRLayer(self):
+ """Return the OGRLayer object
+ """
+ return self.ogrlayer
+
+ def ShapeType(self):
+ """Return the type of the shapes in the shapestore.
+
+ This is either SHAPETYPE_POINT, SHAPETYPE_ARC, SHAPETYPE_POLYGON,
+ SHAEPTYPE_GEOMCOLL, SHAPETYPE_NONE or SHAPETYPE_UNKNOWN.
+ """
+ return self.shapetype
+
+ def RawShapeFormat(self):
+ """Return the raw data format of the shape data, i.e. RAW_PYTHON
+ """
+ return RAW_PYTHON
+
+ def NumShapes(self):
+ """Return the number of shapes in the shape store
+ """
+ return self.numshapes
+
+ def ShapesInRegion(self, bbox):
+ """Return an iterable over the shapes that overlap the bounding box.
+
+ The bbox parameter should be the bounding box as a tuple in the
+ form (minx, miny, maxx, maxy) in the coordinate system of the
+ shape store.
+ """
+ left, bottom, right, top = bbox
+
+ # create a geometry which can be passed to the layer as spatial filter
+ bboxpolygon = ogr.CreateGeometryFromWkt(
+ ('Polygon((%s %s, %s %s, %s %s,%s %s, %s %s))'
+ %(left, bottom, left, top, right, top,
+ right, bottom, left, bottom)))
+
+ if self.ogrlayer.GetSpatialRef():
+ bboxpolygon.AssignSpatialReference(self.ogrlayer.GetSpatialRef())
+
+ self.ogrlayer.ResetReading()
+ #ogrlayer.SetSpatialFilterRect(left, bottom, right, top)
+ self.ogrlayer.SetSpatialFilter(bboxpolygon)
+
+ numFeatures = self.ogrlayer.GetFeatureCount()
+ # if no features are in bbox, return all features as shapesInRegion
+ # (PostGIS sometimes returns no features even if they are within
+ # the bounding box)
+ if numFeatures == 0:
+ self.ogrlayer.SetSpatialFilter(None)
+ numFeatures = self.ogrlayer.GetFeatureCount()
+ for feature in range(numFeatures):
+ nextFeature = self.ogrlayer.GetNextFeature()
+ yield self.shapes[nextFeature.GetFID()]
+
+ self.ogrlayer.SetSpatialFilter(None)
+ bboxpolygon.Destroy()
+
+ def AllShapes(self):
+ """Return an iterable over the shapes in the shape store.
+ """
+ for id in range(len(self.shapes)):
+ yield self.shapes[id]
+
+ def Shape(self, fid):
+ """Return the shape with fid = fid
+ """
+ if fid in self.Table().ids.keys():
+ return self.shapes[fid]
+ else:
+ return None
+
+ def Table(self):
+ """Return the table containing the attribute data."""
+ return self._table
+
+ def Dependencies(self):
+ """Return the empty tuple.
+ """
+ return ()
+
+ def OrigShapeStore(self):
+ """Return None."""
+ return None
+
+ def Id_column(self):
+ """Return the id_column.
+ """
+ return None
+
+class OGRTable(transientdb.AutoTransientTable):
+ """A Table for an ogr datasource.
+ """
+
+ def __init__(self, session, ds, layer, id_column):
+ """Initialize the OGRTable.
+
+ session - should be the current session.
+ ds - should be an instance of OGRDatasource.
+ layer - should be an instance of OGRLayer.
+ id_column - should be the name of the column used as ID column
+ """
+ self.datasource = ds
+ self.layer = layer
+ self.tablename = self.layer.GetName()
+ self.id_column = id_column
+
+ # Map column names and indices to column objects.
+ self.column_map = {}
+
+ # Map feature ids to ordinals.
+ self._map_ords_and_ids()
+
+ self._fetch_table_information()
+ self._fetch_table_content()
+
+ transientdb.AutoTransientTable.__init__(self, session.TransientDB(),
+ self)
+
+ def _fetch_table_information(self):
+ """Internal: Update information about the table
+ """
+ self.columns = []
+
+ layerdefn = self.layer.GetLayerDefn()
+ # if FID column is of interest
+ #col = OGRColumn("FID", table.FIELDTYPE_INT, layerdefn.GetFieldCount())
+ #self.columns.append(col)
+ for i in range(layerdefn.GetFieldCount()):
+ fielddef = layerdefn.GetFieldDefn(i)
+ fieldname = fielddef.GetName()
+ fieldtype = fieldtype_map[fielddef.GetType()]
+ fieldindex = layerdefn.GetFieldIndex(fieldname)
+ col = OGRColumn(fieldname, fieldtype, fieldindex)
+ if col is not None:
+ self.columns.append(col)
+
+ for col in self.columns:
+ self.column_map[col.name] = col
+ self.column_map[col.index] = col
+
+ def _fetch_table_content(self):
+ """Internal: Update information contained in the table
+ """
+ self.content = []
+ layerdefn = self.layer.GetLayerDefn()
+
+ self.layer.ResetReading()
+ for i in range(self.layer.GetFeatureCount()):
+ nextFeature = self.layer.GetNextFeature()
+ row = []
+ for j in range(layerdefn.GetFieldCount()):
+ row.append(nextFeature.GetField(j))
+ # if FID should be listed in the table
+ #if self.id_column is None:
+ # row.append(nextFeature.GetFID())
+ #else:
+ # row.append(nextFeature.GetField(self.id_column))
+ self.content.append(row)
+
+ def _map_ords_and_ids(self):
+ """Create collections which map ordinals to ids and verse visa.
+ """
+ self.ordinals = {}
+ self.ids = {}
+
+ if self.id_column is not None:
+ lay = self.datasource.ExecuteSQL("SELECT %s from %s"
+ %(self.id_column, self.tablename))
+ lay.ResetReading()
+ nextFeature = lay.GetNextFeature()
+ else:
+ self.layer.ResetReading()
+ nextFeature = self.layer.GetNextFeature()
+
+ ord = 0
+ while nextFeature is not None:
+ if self.id_column is not None:
+ id = nextFeature.GetField(self.id_column)
+ nextFeature = lay.GetNextFeature()
+ else:
+ id = nextFeature.GetFID()
+ nextFeature = self.layer.GetNextFeature()
+ self.ordinals[ord] = id
+ self.ids[id] = ord
+ ord = ord + 1
+ if self.id_column is not None:
+ self.datasource.ReleaseResultSet(lay)
+
+ def TableName(self):
+ """Return the name of the table, which is the name of the layer
+ """
+ return self.tablename
+
+ def Title(self):
+ """Return the title of the table.
+ """
+ return self.tablename
+
+ def Dependencies(self):
+ """Return an empty tuple.
+ """
+ return ()
+
+ def NumColumns(self):
+ """Return the number of columns.
+ """
+ return len(self.columns)
+
+ def Columns(self):
+ """Return all columns.
+ """
+ return self.columns
+
+ def Column(self, col):
+ """Return the column col. col can be either a string or an integer.
+ """
+ return self.column_map[col]
+
+ def HasColumn(self, col):
+ """Return if column col exists. col can be either a string or an
+ integer.
+ """
+ return self.column_map.has_key(col)
+
+ def NumRows(self):
+ """Return the number of rows in the table, which equals the number of
+ features in the layer.
+ """
+ return len(self.ids)
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id
+ """
+ if gid < 0:
+ return gid
+ else:
+ ord = self.ids[gid]
+ return ord
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal
+ """
+ if num >= 0:
+ id = self.ordinals[num]
+ return id
+ else:
+ return num
+
+ def ReadRowAsDict(self, row, row_is_ordinal = 0):
+ """Return a dictionary which contains all the fields.
+ """
+ if row_is_ordinal == 0:
+ rowId = self.RowIdToOrdinal(row)
+ else:
+ rowId = row
+ result = {}
+ for i in range(self.NumColumns()):
+ result[self.Column(i).name] = self.content[rowId][i]
+ return result
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ """Return the requested value.
+ """
+ if row_is_ordinal == 0:
+ rowId = self.RowIdToOrdinal(row)
+ else:
+ rowId = row
+ colIndex = self.column_map[col].index
+ return self.content[rowId][colIndex]
+
+ def ValueRange(self, col):
+ """Return the value range of the given column (given as string).
+ """
+
+ result = self.datasource.ExecuteSQL("SELECT min(%s), max(%s) FROM %s"
+ %(col, col, self.layer.GetName()))
+ result.ResetReading()
+ feature = result.GetNextFeature()
+ try:
+ min = feature.GetField(0)
+ max = feature.GetField(1)
+ except:
+ min = 0
+ max = 0
+ self.datasource.ReleaseResultSet(result)
+ return (min, max)
+
+ def UniqueValues(self, col):
+ """Return all the values being found in the column (given as string).
+ """
+ result = self.datasource.ExecuteSQL((
+ "SELECT DISTINCT %s FROM %s ORDER BY %s"
+ %(col,self.layer.GetName(),col)))
+ values = []
+ while 1:
+ feature = result.GetNextFeature()
+ if feature is None:
+ break
+ values.append(feature.GetField(0))
+ self.datasource.ReleaseResultSet(result)
+ return values
+
+ def SimpleQuery(self, left, comparison, right):
+ """Return the FIDs resulting from the given query.
+ """
+
+ if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
+ raise ValueError("Comparison operator %r not allowed" %comparison)
+
+ if comparison == "==":
+ comparison = "="
+
+ if isinstance(right, OGRColumn):
+ right_template = right.name
+ else:
+ right_template = right
+
+ if self.id_column is None:
+ id = "FID"
+ else:
+ id = self.id_column
+ query = ("SELECT %s FROM %s WHERE %s %s %s ORDER BY %s"
+ % (id, self.tablename,left.name, comparison,
+ right_template, id))
+
+ lay = self.datasource.ExecuteSQL(query)
+ result = []
+ while lay is not None:
+ feature = lay.GetNextFeature()
+ if feature is None:
+ break
+ result.append(feature.GetField(0))
+ if lay is not None:
+ self.datasource.ReleaseResultSet(lay)
+ return result
+
+ def Id_column(self):
+ """Return the id_column.
+ """
+ return self.id_column
+
+
+class OGRColumn:
+ """Column description for a table for an ogr file
+ """
+
+ def __init__(self, name, type, index):
+ self.name = name
+ self.type = type
+ self.index = index
Added: packages/thuban/branches/upstream/current/Extensions/ogr/ogrstart.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/ogrstart.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/ogrstart.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,238 @@
+# Copyright (c) 2004,2006 by Intevation GmbH vim:encoding=latin-1:
+# Authors:
+# Nina Hüffmeyer <nhueffme at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2721 $"
+# $Source$
+# $Id: ogrstart.py 2721 2007-01-13 15:11:42Z dpinte $
+
+# Needed wx.-toolkit classes
+import wx
+
+# We need os.path
+import os
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+from Thuban.Model.layer import Layer
+
+# Import ogr related classes
+from Extensions.ogr import ogrshapes, ogrdialog
+from Extensions.ogr.ogrdialog import ChooseOGRDBTableDialog
+
+from Thuban.UI.menu import Menu
+from Thuban.UI.mainwindow import _has_dbconnections, _has_gdal_support
+
+def open_with_ogr(context):
+ '''Open a file supported by ogr.
+ '''
+ canvas = context.mainwindow.canvas
+ map = canvas.Map()
+
+ # Get the file to be opened
+ dlg = wx.FileDialog(canvas, _("Select a data file"),
+ context.application.Path("data"), "",
+ _("Shapefiles (*.shp)") + "|*.shp|" +
+ _("GML files (*.gml)") + "|*.gml|" +
+ _("MapInfo files (*.tab)") + "|*.tab|" +
+ _("DGN files (*.dgn)") + "|*.dgn|" +
+ _("CSV files (*.csv)") + "|*.csv|" +
+ _("All Files (*.*)") + "|*.*|",
+ wx.OPEN | wx.MULTIPLE)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ filenames = dlg.GetPaths()
+ for filename in filenames:
+ title = os.path.splitext(os.path.basename(filename))[0]
+ has_layers = map.HasLayers()
+ layerDlg = ogrdialog.ChooseLayer(canvas, filename)
+ if layerDlg.ShowModal() == wx.ID_OK:
+ layername = layerDlg.GetLayer()
+ try:
+ session = context.application.Session()
+ store = OpenFileShapestore(context.mainwindow, session,
+ filename, layername)
+ session.AddShapeStore(store)
+ except:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(_("Add Layer"),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ if store is not None:
+ layer = Layer(title, store)
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ canvas.FitMapToWindow()
+ context.application.SetPath("data",filename)
+ dlg.Destroy()
+
+def select_file_format(context):
+ ''' Display all available supported formats.
+ '''
+
+ canvas = context.mainwindow.canvas
+ file = None
+ map = canvas.Map()
+
+ session = context.application.Session()
+
+ dlg = ogrdialog.ChooseFileFormat(canvas, session)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ pass
+ dlg.Destroy()
+
+def open_db(context):
+ ''' Open a table in a database as a layer.
+ '''
+
+ canvas = context.mainwindow.canvas
+ map = canvas.Map()
+
+ session = context.application.Session()
+ dlg = ChooseOGRDBTableDialog(canvas, session)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ dbconn, connString, dbtable, id_column = dlg.GetTable()
+ try:
+ store = OpenDBShapestore(session, dbconn, dbtable, id_column,
+ None)
+ session.AddShapeStore(store)
+
+ layer = Layer(dbtable, store)
+
+ has_layers = map.HasLayers()
+ map.AddLayer(layer)
+ if not has_layers:
+ canvas.FitMapToWindow()
+ except:
+ # Some error occured while initializing the layer
+ context.mainwindow.RunMessageBox(_("Add Layer from database"),
+ _("Can't open the database table '%s'")
+ % dbtable)
+ dlg.Destroy()
+
+def open_OGRConnection(context):
+ """Open a datasource with an OGRConnection string."""
+ canvas = context.mainwindow.canvas
+ map = canvas.Map()
+
+ session = context.application.Session()
+ dlg = ogrdialog.OGRConnectionDialog(canvas, session)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ dsname = dlg.GetDatasourceName()
+
+ layerDlg = ogrdialog.ChooseLayer(canvas, dsname)
+ if layerDlg.ShowModal() == wx.ID_OK:
+ layername = layerDlg.GetLayer()
+ try:
+ store = ogrshapes.OGRShapeStore(session, dsname, layername)
+ session.AddShapeStore(store)
+ except:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(("Add Layer"),
+ ("Can't open the file '%s'.") % dsname)
+ else:
+ layer = Layer(dsname, store)
+ has_layers = map.HasLayers()
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ canvas.FitMapToWindow()
+ dlg.Destroy()
+
+def OpenFileShapestore(mainwindow, session, filename, layername):
+ """Open a datasource and add the required layer.
+ """
+ try:
+ store = ogrshapes.OGRFileShapeStore(session, filename, layername)
+ return store
+ except:
+ # Some error occured while initializing the layer
+ mainwindow.RunMessageBox(_("Open datasource"),
+ _("Can't open the datasource '%s'")
+ % filename)
+ return None
+
+def OpenDBShapestore(session, dbconn, layername, id_column, geo_column):
+ """Open a datasource and add the required layer.
+
+ dbconn - shold be a DBConnection
+ layername - the name of the table which should opened as layer
+ id_column - the column name which should be used as ID column
+ geo_column - always None for ogr
+ """
+ try:
+ filename = "PG: dbname=%s" %dbconn.dbname
+ if dbconn.host is not "":
+ filename = filename + " host=%s" % dbconn.host
+ if dbconn.user is not "":
+ filename = filename + " user=%s" % dbconn.user
+ if dbconn.password is not "":
+ filename = filename + " password=%s" % dbconn.password
+ if dbconn.port is not "":
+ filename = filename + " port=%s" % dbconn.port
+ store = ogrshapes.OGRShapeStore(session, filename, layername,
+ id_column = id_column)
+ return store
+ except:
+ # Some error occured while initializing the layer
+ context.mainwindow.RunMessageBox(_("Open datasource"),
+ _("Can't open the datasource '%s'")
+ % filename)
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+
+# find the map menu (create a new if not found)
+#map_menu = main_menu.FindOrInsertMenu('map', _('Map'))
+#ogr_menu = Menu("ogr", _("Open layer via OGR"),[])
+# as long as there we are not stable, better add to "Extentions" marked "beta"
+map_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+ogr_menu = Menu("ogr", _("(testing) Open layer via OGR"),[])
+
+
+ogrsupport = ogrshapes.has_ogr_support()
+
+# create new commands and register them
+registry.Add(Command('open_ogr_files', 'Open an ogr-file', open_with_ogr,
+ sensitive = _has_gdal_support,
+ helptext = 'Open a file supported from ogr'))
+
+#registry.Add(Command('select_file_format', 'Select a file format',
+# select_file_format,
+# helptext = "Select a file format supported from ogr"))
+
+registry.Add(Command('open_db', 'Open a layer from a database',
+ open_db,
+ sensitive = _has_dbconnections,
+ helptext = "Open a layer from a database, e.g. PostGIS"))
+
+registry.Add(Command('open_OGRConnection',
+ ("Open a datasource with an OGRConnection string"),
+ open_OGRConnection,
+ sensitive = _has_gdal_support, helptext =
+ "Open a datasource with an OGRConnection string"))
+
+# finally bind the new command with an entry in the extensions menu
+ogr_menu.InsertItem("open_ogr_files")
+#ogr_menu.InsertItem('select_file_format')
+ogr_menu.InsertItem('open_db')
+ogr_menu.InsertItem('open_OGRConnection')
+
+# Add ogr menu to map menu
+map_menu.InsertItem(ogr_menu, after = "rasterlayer_add")
Added: packages/thuban/branches/upstream/current/Extensions/ogr/test/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/test/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/test/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,7 @@
+# -*- coding: iso-8859-1 -*- vim:encoding=latin-1:
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Nina Hüffmeyer <nhueffme at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
Added: packages/thuban/branches/upstream/current/Extensions/ogr/test/test_OGRShapestore.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/test/test_OGRShapestore.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/test/test_OGRShapestore.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,256 @@
+# Copyright (C) 2004,2006 by Intevation GmbH vim:encoding=latin-1:
+# Authors:
+# Nina Hüffmeyer <nhueffme at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+__version__ = "$Revision: 2713 $"
+# $Source$
+# $Id: test_OGRShapestore.py 2713 2006-10-26 16:37:42Z bernhard $
+
+"""Tests for ogrshapes"""
+
+import os
+import sys
+import unittest
+
+try:
+ import ogr
+ ogr_imported = True
+except ImportError:
+ # No ogr available. The tests will
+ # be skipped completely.
+ ogr_imported = False
+
+# If run directly as a script, add Thuban's test directory to the path
+# as well as the extensions own directory (i.e. parent).
+# Otherwise we assume that the importing code has already done it.
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ "..", "..", "test"))
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ ".."))
+
+import support
+support.initthuban()
+
+from Extensions.ogr.ogrshapes import OGRShapeStore, OGRShape, \
+ SHAPETYPE_POINT, SHAPETYPE_ARC, SHAPETYPE_POLYGON
+from Thuban.Model.data import RAW_PYTHON
+from Thuban.Model.table import FIELDTYPE_INT
+from Thuban.Model.session import Session
+
+
+def skip_if_no_ogr():
+ if not ogr_imported:
+ raise support.SkipTest( \
+ "Can't run ogr tests because ogr couldn't be imported.")
+
+class TestOGRShapeStore_shp(unittest.TestCase, support.FloatComparisonMixin):
+
+ def setUp(self):
+ """Initialize self.session and open shapefile, if ogr could be
+ imported.
+ """
+ skip_if_no_ogr()
+ self.session = Session("TestSession")
+ self.filename_arc = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ self.store_arc = OGRShapeStore(self.session, self.filename_arc,
+ "roads-line")
+
+ self.filename_point = os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.shp")
+ self.store_point = OGRShapeStore(self.session, self.filename_point,
+ "cultural_landmark-point")
+
+ self.filename_poly = os.path.join("..", "Data", "iceland",
+ "political.shp")
+ self.store_poly = OGRShapeStore(self.session, self.filename_poly,
+ "political")
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session = None
+ self.store_arc = None
+ self.store_point = None
+ self.store_poly = None
+
+ def test_shape_type(self):
+ """Test OGRShapeStore.ShapeType() with arc shapes"""
+ self.assertEquals(self.store_arc.ShapeType(), SHAPETYPE_ARC)
+ self.assertEquals(self.store_point.ShapeType(), SHAPETYPE_POINT)
+ self.assertEquals(self.store_poly.ShapeType(), SHAPETYPE_POLYGON)
+
+ def test_raw_format(self):
+ """Test OGRShapeStore.RawShapeFormat() with ogr file"""
+ self.assertEquals(self.store_arc.RawShapeFormat(), RAW_PYTHON)
+ self.assertEquals(self.store_point.RawShapeFormat(), RAW_PYTHON)
+ self.assertEquals(self.store_poly.RawShapeFormat(), RAW_PYTHON)
+
+ def test_boundingbox(self):
+ """Test OGRShapeStore.BoundingBox() with arc shapes"""
+ self.assertFloatSeqEqual(self.store_arc.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+ self.assertFloatSeqEqual(self.store_point.BoundingBox(),
+ [-23.806047439575195, 63.405960083007812,
+ -15.12291431427002, 66.36572265625])
+ self.assertFloatSeqEqual(self.store_poly.BoundingBox(),
+ [-24.546524047851562, 63.286754608154297,
+ -13.495815277099609, 66.563774108886719])
+
+ def test_num_shapes(self):
+ """Test OGRShapeStore.NumShapes() with arc shapes"""
+ self.assertEquals(self.store_arc.NumShapes(), 839)
+ self.assertEquals(self.store_point.NumShapes(), 34)
+ self.assertEquals(self.store_poly.NumShapes(), 156)
+
+ def test_shapes_in_region(self):
+ """Test OGRShapeStore.ShapesInRegion() with arc shapes"""
+ shapes_arc = self.store_arc.ShapesInRegion((-22.78, 63.96,
+ -22.72, 64.0))
+ self.assertEquals([s.ShapeID() for s in shapes_arc], [769, 771])
+
+ shapes_point = self.store_point.ShapesInRegion((-23.0, 63.0,
+ -22.0, 64.0))
+ self.assertEquals([s.ShapeID() for s in shapes_point], [29, 31])
+
+ shapes_poly = self.store_poly.ShapesInRegion((-23.0, 63.0, -22.0, 64.0))
+ self.assertEquals([s.ShapeID() for s in shapes_poly], [144])
+
+ def test_all_shapes(self):
+ """Test OGRShapeStore.AllShapes()"""
+ self.assertEquals([s.ShapeID() for s in self.store_arc.AllShapes()],
+ range(self.store_arc.NumShapes()))
+ self.assertEquals([s.ShapeID() for s in self.store_point.AllShapes()],
+ range(self.store_point.NumShapes()))
+ self.assertEquals([s.ShapeID() for s in self.store_poly.AllShapes()],
+ range(self.store_poly.NumShapes()))
+
+ def test_shape_Points(self):
+ """Test OGRShapeStore.Shape() with arc shapes"""
+ self.assertPointListEquals(self.store_arc.Shape(32).Points(),
+ [[(-15.08217430114746, 66.2773818969726),
+ (-15.02635002136230, 66.2733917236328)]])
+ self.assertPointListEquals(self.store_point.Shape(13).Points(),
+ [[(-15.364621162414551, 65.6103515625)]])
+ self.assertPointListEquals(self.store_poly.Shape(20).Points(),
+ [[(-22.233562469482422, 64.4395751953125),
+ (-22.244234085083008, 64.441192626953125),
+ (-22.233894348144531, 64.446701049804688),
+ (-22.226711273193359, 64.44439697265625),
+ (-22.23356246948242, 64.4395751953125)]])
+
+ def test_shape_shapeid(self):
+ """Test OGRShapeStore.Shape(i).ShapeID()"""
+ self.assertEquals(self.store_arc.Shape(5).ShapeID(), 5)
+ self.assertEquals(self.store_point.Shape(13).ShapeID(), 13)
+ self.assertEquals(self.store_point.Shape(20).ShapeID(), 20)
+
+ def test_shape_compute_bbox(self):
+ """Test bbox of one shape"""
+ self.assertFloatSeqEqual(self.store_arc.Shape(32).compute_bbox(),
+ (-15.08217430114746, 66.2733917236328,
+ -15.02635002136230, 66.2773818969726))
+ self.assertFloatSeqEqual(self.store_point.Shape(13).compute_bbox(),
+ (-15.364621162414551, 65.6103515625,
+ -15.364621162414551, 65.6103515625))
+ self.assertFloatSeqEqual(self.store_poly.Shape(20).compute_bbox(),
+ (-22.244234085083008, 64.4395751953125,
+ -22.226711273193359, 64.446701049804688))
+
+
+class TestOGRTable(unittest.TestCase, support.FloatComparisonMixin):
+
+ def setUp(self):
+ """Initialize"""
+ skip_if_no_ogr()
+ self.session = Session("TestSession")
+ self.filename = os.path.join("..","Data", "iceland","roads-line.shp")
+ self.store_arc = OGRShapeStore(self.session, self.filename,
+ "roads-line")
+ self.table = self.store_arc.Table()
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session = None
+ self.store_arc = None
+ self.table = None
+
+ def test_Dependencies(self):
+ """Test dependencies, which is always ()"""
+ self.assertEquals(self.table.Dependencies(), ())
+
+ def test_NumColumns(self):
+ """Test number of columns"""
+ self.assertEquals(self.table.NumColumns(), 9)
+
+ def test_Columns(self):
+ """Test columns, which are instances of OGRColumn"""
+ self.assertEquals(len(self.table.Columns()), 9)
+ self.assertEquals(self.table.Columns()[0].name, "FNODE_")
+ self.assertEquals(self.table.Columns()[0].type, FIELDTYPE_INT)
+ self.assertEquals(self.table.Columns()[0].index, 0)
+
+ def test_Column(self):
+ """Test column, which is instance of OGRColumn"""
+ self.assertEquals(self.table.Column(0).name, "FNODE_")
+ self.assertEquals(self.table.Column(0).type, FIELDTYPE_INT)
+ self.assertEquals(self.table.Column(0).index, 0)
+ self.assertEquals(self.table.Column("FNODE_").type, FIELDTYPE_INT)
+ self.assertEquals(self.table.Column("FNODE_").index, 0)
+
+ def test_HasColumn(self):
+ """Test HasColumn(), which can be called either with an integer or
+ a string"""
+ self.assert_(self.table.HasColumn(0))
+ self.assert_(self.table.HasColumn("FNODE_"))
+
+ def test_NumRows(self):
+ """Test number of rows, which equals the number of features"""
+ self.assertEquals(self.table.NumRows(), 839)
+
+ def test_RowIdToOrdinal(self):
+ self.assertEqual(self.table.RowIdToOrdinal(5),5)
+
+ def test_RowOrdinalToId(self):
+ self.assertEqual(self.table.RowOrdinalToId(5),5)
+
+ def test_ReadRowAsDict(self):
+ """Test ReadRowAsDict()"""
+ self.assertEquals(len(self.table.ReadRowAsDict(0)), 9)
+ self.assertEquals(self.table.ReadRowAsDict(0, row_is_ordinal = 1),
+ {"FNODE_": 3,
+ "TNODE_": 1,
+ "LPOLY_": 146,
+ "RPOLY_": 146,
+ "LENGTH": 0.156,
+ "RDLINE_": 1,
+ "RDLINE_ID": 879,
+ "RDLNTYPE": 3,
+ "RDLNSTAT": 1})
+
+ def test_ReadValue(self):
+ """Test ReadValue()"""
+ self.assertEquals(self.table.ReadValue(0,0,0), 3)
+ self.assertEquals(self.table.ReadValue(0,"FNODE_",0),3)
+
+ def test_ValueRange(self):
+ """Test ValueRange()"""
+ self.assertEquals(self.table.ValueRange("FNODE_"), (1, 733))
+
+ def test_UniqueValues(self):
+ """Test UniqueValues()"""
+ self.assertFloatSeqEqual(self.table.UniqueValues("RDLNTYPE"), [2,3,8])
+
+ def test_SimpleQuery(self):
+ """Test SimpleQuery()"""
+ self.assertEquals(self.table.SimpleQuery(self.table.Column("LENGTH"),
+ "==", 0.156),[0, 24, 317])
+
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/Extensions/ogr/x.diff
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/ogr/x.diff 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/ogr/x.diff 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,103 @@
+Index: test/__init__.py
+===================================================================
+--- test/__init__.py (Revision 2711)
++++ test/__init__.py (Arbeitskopie)
+@@ -1,4 +1,4 @@
+-# -*- coding: iso-8859-1 -*-
++# -*- coding: iso-8859-1 -*- vim:encoding=latin-1:
+ # Copyright (C) 2004 by Intevation GmbH
+ # Authors:
+ # Nina Hüffmeyer <nhueffme at intevation.de>
+Index: test/test_OGRShapestore.py
+===================================================================
+--- test/test_OGRShapestore.py (Revision 2711)
++++ test/test_OGRShapestore.py (Arbeitskopie)
+@@ -1,6 +1,6 @@
+-# Copyright (C) 2004,2006 by Intevation GmbH
++# Copyright (C) 2004,2006 by Intevation GmbH vim:encoding=latin-1:
+ # Authors:
+-# Nina Hueffmeyer <nhueffme at intevation.de>
++# Nina Hüffmeyer <nhueffme at intevation.de>
+ #
+ # This program is free software under the GPL (>=v2)
+ # Read the file COPYING coming with the software for details.
+Index: ogrshapes.py
+===================================================================
+--- ogrshapes.py (Revision 2711)
++++ ogrshapes.py (Arbeitskopie)
+@@ -1,6 +1,6 @@
+-# Copyright (C) 2004 by Intevation GmbH
++# Copyright (C) 2004 by Intevation GmbH vim:encoding=latin-1:
+ # Authors:
+-# Nina Hueffmeyer <nhueffme at intevation.de>
++# Nina Hüffmeyer <nhueffme at intevation.de>
+ #
+ # This program is free software under the GPL (>=v2)
+ # Read the file COPYING coming with the software for details.
+Index: __init__.py
+===================================================================
+--- __init__.py (Revision 2711)
++++ __init__.py (Arbeitskopie)
+@@ -1,6 +1,6 @@
+-# Copyright (C) 2004 by Intevation GmbH
++# Copyright (C) 2004 by Intevation GmbH vim:encoding=latin-1:
+ # Authors:
+-# Nina Hueffmeyer <nhueffme at intevation.de>
++# Nina Hüffmeyer <nhueffme at intevation.de>
+ #
+ # This program is free software under the GPL (>=v2)
+ # Read the file COPYING coming with the software for details.
+@@ -25,12 +25,12 @@
+ # in the global test routine.
+
+ # perform the registration of the extension
+-from Thuban import _
++from Thuban import _, internal_from_unicode
+ from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ ext_registry.add(ExtensionDesc(
+ name = 'OGRstart',
+ version = '0.9.0',
+- authors= [ 'Nina Hueffmeyer' ],
++ authors= [ internal_from_unicode(u'Nina H\xfcffmeyer') ],
+ copyright = '2004 Intevation GmbH',
+ desc = _("Open a file supported by ogr.")))
+Index: ogrstart.py
+===================================================================
+--- ogrstart.py (Revision 2711)
++++ ogrstart.py (Arbeitskopie)
+@@ -1,4 +1,4 @@
+-# Copyright (c) 2004 by Intevation GmbH
++# Copyright (c) 2004,2006 by Intevation GmbH vim:encoding=latin-1:
+ # Authors:
+ # Nina Hüffmeyer <nhueffme at intevation.de>
+ #
+@@ -199,9 +199,13 @@
+
+
+ # find the map menu (create a new if not found)
+-map_menu = main_menu.FindOrInsertMenu('map', _('Map'))
+-ogr_menu = Menu("ogr", _("Open layer via OGR"),[])
++#map_menu = main_menu.FindOrInsertMenu('map', _('Map'))
++#ogr_menu = Menu("ogr", _("Open layer via OGR"),[])
++# as long as there we are not stable, better add to "Extentions" marked "beta"
++map_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
++ogr_menu = Menu("ogr", _("(testing) Open layer via OGR"),[])
+
++
+ ogrsupport = ogrshapes.has_ogr_support()
+
+ # create new commands and register them
+Index: ogrdialog.py
+===================================================================
+--- ogrdialog.py (Revision 2711)
++++ ogrdialog.py (Arbeitskopie)
+@@ -1,6 +1,6 @@
+-# Copyright (c) 2001, 2003, 2004 by Intevation GmbH
++# Copyright (c) 2001, 2003, 2004 by Intevation GmbH vim:encoding=latin-1:
+ # Authors:
+-# Martin Mueller <mmueller at intevation.de>
++# Martin Müller <mmueller at intevation.de>
+ # Bernhard Herzog <bh at intevation.de>
+ #
+ # This program is free software under the GPL (>=v2)
Added: packages/thuban/branches/upstream/current/Extensions/profiling/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/profiling/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/profiling/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,22 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# import the actual module
+import profiling
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'profiling',
+ version = '1.0.0',
+ authors= [ 'Bernhard Herzog' ],
+ copyright = '2003, 2004 Intevation GmbH',
+ desc = _("Provide a profiler and a timer\n"
+ "for screen rendering.")))
+
Added: packages/thuban/branches/upstream/current/Extensions/profiling/profiling.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/profiling/profiling.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/profiling/profiling.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,148 @@
+# Copyright (C) 2003, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2003)
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Performance Measurement
+
+This module implements two Thuban commands in a new Profiling menu:
+
+ Profile Screen Render -- Run the screen rendering code in a profile
+
+ Time Screen Render -- Measure the time taken for a complete redraw
+
+See the individual functions for more details.
+"""
+
+__version__ = "$Revision: 2721 $"
+# $Source$
+# $Id: profiling.py 2721 2007-01-13 15:11:42Z dpinte $
+
+import os
+import StringIO
+import sys
+import tempfile
+import profile
+import time
+import pstats
+
+from wx.lib.dialogs import ScrolledMessageDialog
+
+from Thuban import _
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu
+
+#
+# Customization
+#
+# Assign to these in your ~/.thuban/thubanstart
+
+# The machine specific profiler bias. See the standard python profile
+# module for details on how to find out which value to use.
+profiler_bias = 0
+
+# The directory the profile output is to be written to
+# (Call mktemp once to initialize tempfile.tempdir)
+tempfile.mktemp()
+profile_dir = tempfile.tempdir
+
+# Wether to pop up a dialog box with the result.
+popup_dialog_box = True
+
+
+#
+# Timing and profiling a complete redraw
+#
+
+def do_redraw(context):
+ """Perform a complete redraw in the canvas in context"""
+ canvas = context.mainwindow.canvas
+
+ # Make sure there are no no finished bitmaps and active renderer
+ canvas.full_redraw()
+
+ # Iterate until all is drawn
+ for c in canvas._render_iterator():
+ pass
+
+
+#
+# Profiling the redraw
+#
+
+
+def profile_screen_renderer(context):
+ """Script to run the redraw in the profiler
+
+ The data gathered by the profiler will be written to
+ <TMPDIR>/thuban-render.profile (<TMPDIR> is your system specific
+ temporary directory.
+
+ See the python documentation of the profile and pstats modules for
+ how to access the data in the generated .profile file.
+ """
+ print "profiling screen renderer...",
+ sys.stdout.flush()
+ prof = profile.Profile(bias = profiler_bias)
+ prof.runctx("do_redraw(context)", globals(), locals())
+ filename = os.path.join(profile_dir, "thuban-render.profile")
+ prof.dump_stats(filename)
+ print "done and saved to", filename
+
+ if popup_dialog_box:
+ # catch the printout to stdout so that we can present the
+ # text in a dialog
+ f = StringIO.StringIO()
+ orig_stdout = sys.stdout
+ sys.stdout = f
+ try:
+ p = pstats.Stats(filename)
+ msg = _('These are the statistics sorted by cumulative time:')
+ p.strip_dirs().sort_stats('cumulative').print_stats()
+ m = f.getvalue()
+ msg = '%s\n\n%s' % (msg, m)
+ finally:
+ sys.stdout = orig_stdout
+
+ dlg = ScrolledMessageDialog(context.mainwindow, msg,
+ _('Profile Screen Render'))
+ dlg.ShowModal()
+
+
+registry.Add(Command("profile_screen_renderer", _('Profile Screen Render'),
+ profile_screen_renderer,
+ helptext = _('Profile the screen render')))
+
+
+#
+# Timing the redraw
+#
+
+def time_screen_renderer(context):
+ """Script to measure the time of a complete redraw.
+
+ The time taken will be printed to stdout.
+ """
+ start = time.clock()
+ do_redraw(context)
+ duration = time.clock() - start
+ msg = _('Redraw finished in %g seconds.') % duration
+ if popup_dialog_box:
+ context.mainwindow.RunMessageBox(_('Time Screen Render'), msg)
+ else:
+ print msg
+
+
+registry.Add(Command("time_screen_renderer", _('Time Screen Render'),
+ time_screen_renderer,
+ helptext = _('Time the screen render')))
+
+# find the extensions menu (create it anew if not found)
+extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+profiler_menu = extensions_menu.InsertMenu("profiler", _('&Profiler'))
+profiler_menu.InsertItem("time_screen_renderer")
+profiler_menu.InsertItem("profile_screen_renderer")
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,33 @@
+# Copyright (C) 2004, 2005, 2006, 20007 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2004)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+# import the actual modules
+from os import environ
+from sys import platform
+try:
+ if platform != 'win32':
+ dummy = environ["DISPLAY"]
+ import svgsaver
+ import maplegend
+except:
+ pass # For non-win32 platform, we don't have a DISPLAY, so don't import
+ # the modules (for test mode)
+ # For win32 platform, there is always have a graphical mode
+ # Not sure whether this is the best method to avoid problems
+ # in the global test routine.
+
+# perform the registration of the extension
+from Thuban import _
+from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+
+ext_registry.add(ExtensionDesc(
+ name = 'SVG Export',
+ version = '1.0.1',
+ authors= [ 'Markus Rechtien', 'Bernhard Reiter' ],
+ copyright = '2004-2007 Intevation GmbH',
+ desc = _("Export the current map and legend in Thuban-map-SVG format.")))
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/maplegend.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/maplegend.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/maplegend.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,178 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Markus Rechtien <markus at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2721 $"
+# $Source$
+# $Id: maplegend.py 2721 2007-01-13 15:11:42Z dpinte $
+
+
+"""
+Write a basic map legend in svg format.
+"""
+
+
+# Needed wx.-toolkit classes
+import wx
+
+# We need os.path
+import os
+
+# Use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Color related classes defined in the thuban model
+from Thuban.Model.color import Transparent, Color, Black
+
+# Different shape types
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
+ SHAPETYPE_POINT, RAW_SHAPEFILE
+
+# Import SVG related classes
+from svgmapwriter import SVGRenderer, VirtualDC, TRANSPARENT_PEN, \
+ TRANSPARENT_BRUSH, SOLID, Pen, Brush, Point
+
+
+BLACK_PEN = Pen()
+
+class SVGMapLegend(SVGRenderer):
+ """Class to render a basic map legend.
+
+ """
+ def __init__(self, dc, map=None, scale=(1.0), offset=(0,0),
+ region=(0,0,0,0), resolution = 72.0,
+ honor_visibility = 1, destination_region = (0,0,0,0)):
+ SVGRenderer.__init__(self, dc, map, scale, offset, region,
+ resolution, honor_visibility)
+ self.destination_region = destination_region
+ self.factor = 1.0
+
+ def RenderLegend(self, layers):
+ """Render the legend on the Map."""
+ dc = self.dc
+ dc.SetPen(BLACK_PEN)
+ dc.SetBrush(TRANSPARENT_BRUSH)
+ # Dimension stuff
+ width, height = dc.GetSizeTuple()
+ mminx, mminy, mmaxx, mmaxy = self.destination_region
+ textwidth, textheight = dc.GetTextExtent("0")
+ iconwidth = iconheight = textheight
+ stepy = 12
+ dx = 12
+ posx = mmaxx + 20 + 10 # 20 pix distance mapframe/legend frame,
+ # 10 pix inside legend frame
+ posy = mminy + 20 # 20 pix inside legend frame
+ #
+ self.dc.BeginGroup(meta={'Object':'legend', })
+ # Render the legend
+ dc.SetTextForeground(Black)
+ if layers:
+ layers.reverse()
+ for l in layers:
+ if l.Visible():
+ # Render title
+ dc.DrawText(l.Title(), posx, posy)
+ posy+=stepy
+ if l.HasClassification():
+ # Render classification
+ clazz = l.GetClassification()
+ shapeType = l.ShapeType()
+ for g in clazz:
+ if g.IsVisible():
+ self.Draw(dc, wx.Rect(posx+dx,
+ posy-iconheight+2,
+ iconwidth, iconheight),
+ g.GetProperties(), shapeType)
+ dc.DrawText(g.GetDisplayText(),
+ posx+2*dx+iconwidth, posy)
+ posy+=stepy
+ posy+=10
+ self.dc.EndGroup()
+
+ def Draw(self, dc, rect, prop, shapeType):
+ '''Draw little icon for a shape depending on given properties.'''
+ x = rect.GetX()
+ y = rect.GetY()
+ w = rect.GetWidth()
+ h = rect.GetHeight()
+
+ pen, brush = self.tools_for_property(prop)
+ dc.SetPen(pen)
+ dc.SetBrush(brush)
+
+ if shapeType == SHAPETYPE_ARC:
+ dc.DrawSpline([Point(x, y + h),
+ Point(x + w/2, y + h/4),
+ Point(x + w/2, y + h/4*3),
+ Point(x + w, y)])
+
+ elif shapeType == SHAPETYPE_POINT:
+ dc.DrawCircle(x + w/2, y + h/2,
+ (min(w, h) - prop.GetLineWidth())/2)
+
+ elif shapeType == SHAPETYPE_POLYGON:
+ dc.DrawRectangle(x, y, w, h)
+
+
+def write_legend(context):
+ """Export the data depending on the set properties.
+
+ This is the main export function.
+ """
+ canvas = context.mainwindow.canvas
+ file = None
+ map = canvas.Map()
+ #
+ if hasattr(canvas, "export_path"):
+ export_path = canvas.export_path
+ else:
+ export_path="."
+ # Get the file the session shall be written to
+ dlg = wx.FileDialog(canvas, _("Write SVG"), export_path, "",
+ "Scalable Vector Graphics (*.svg)|*.svg",
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ #
+ response = dlg.ShowModal()
+ if response == wx.ID_OK:
+ file = dlg.GetPath()
+ else: # Do nothing if choice was interrupted.
+ return 0
+
+ # If the user selected a file
+ if file and map is not None:
+ canvas.export_path = os.path.dirname(file)
+ width, height = canvas.GetSizeTuple()
+ llx, lly = canvas.win_to_proj(0, height)
+ urx, ury = canvas.win_to_proj(width, 0)
+ mapwidth, mapheight = ((urx - llx), (ury - lly))
+ #
+ selected_layer = map.Layers()
+ dc = VirtualDC(file, (mapwidth, mapheight, ))
+ dc.BeginExport()
+ #
+ renderer = SVGMapLegend(dc)
+ renderer.RenderLegend(selected_layer)
+ #
+ dc.EndExport()
+
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+# create a new command and register it
+registry.Add(Command('write_legend', _('Write SVG Legend'), write_legend,
+ helptext = _('Write a basic Legend for the map.')))
+
+# find the menu we want to be in (create it anew if not found)
+menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally bind the new command with an entry in the extensions menu
+menu.InsertItem('write_legend')
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/svgmapwriter.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/svgmapwriter.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/svgmapwriter.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,784 @@
+# Copyright (c) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Markus Rechtien <markus at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de> (2004, 2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""
+Classes needed to write a session in SVG format.
+"""
+
+# For compatibility with python 2.2
+from __future__ import generators
+
+
+__version__ = "$Revision: 2732 $"
+# $Source$
+# $Id: svgmapwriter.py 2732 2007-02-26 23:02:25Z bernhard $
+
+import sys
+
+# Verboseness level for debugging. Useful values: 0,1,2,3
+verbose=0
+log=sys.stdout.write
+
+# Regular expressions used with Fontnames
+import re
+# Combining strings
+from string import join
+# We need to determine some object types
+from types import ListType
+# for SetBaseID
+import binascii
+
+from Thuban import _
+from Thuban.Model.data import SHAPETYPE_POINT, SHAPETYPE_ARC
+# VirtualDC extends XMLWriter
+from Thuban.Model.xmlwriter import XMLWriter, escape
+# Color related classes from the model of thuban
+from Thuban.Model.color import Transparent, Black
+# The SVGRenderer is subclass of BaseRenderer
+from Thuban.UI.baserenderer import BaseRenderer
+
+# Basic font map.
+fontMap = { "Times" : re.compile("Times-Roman.*"),
+ "Helvetica" : re.compile("Helvetica.*"),
+ "Courier" : re.compile("Courier.*"),
+ }
+
+# Possible values for svg line joins.
+svg_joins = {'miter':'miter', 'round':'round', 'bevel':'bevel'}
+# Possible values for svg line caps.
+svg_caps = {'':'', 'butt':'butt', 'round':'round', 'square':'square'}
+
+#
+# Some pseudo classes to be compatible with the Baserenderer-class.
+#
+class Point:
+ """Simple Point class to save x,y coordinates."""
+ def __init__(self, xp=0, yp=0):
+ self.x = xp
+ self.y = yp
+
+ def __repr__(self):
+ return "Point(%s, %s)" % (str(self.x), str(self.y))
+
+class Trafo:
+ """Class for transformation properties transfer."""
+ def __init__(self):
+ self.trafos = []
+
+ def Append(self, type, coeffs):
+ """Append a transformation to the list."""
+ self.trafos.append((type, coeffs))
+
+ def Count(self):
+ """Get the number of transformations in list."""
+ return len(self.trafos)
+
+ def Pop(self):
+ """Pop and return a transformation from the end of the list."""
+ if len(self.trafos) > 0:
+ return self.trafos.pop()
+ else: return None
+
+class Pattern:
+ def __init__(self, solid=1):
+ self.solid = solid
+
+class Pen:
+ """Pen object for property transfer."""
+ def __init__(self, pcolor = Black, pwidth = 1, pdashes = None):
+ self.color = pcolor
+ self.width = pwidth
+ self.dashes = pdashes
+ self.join = 'round'
+ self.cap = 'round'
+
+ def __str__(self):
+ return "Pen(%s,%s,%s,%s,%s)" % \
+ (str(self.color), str(self.width), str(self.dashes),
+ str(self.join), str(self.cap))
+
+ def GetColor(self):
+ return self.color
+
+ def GetWidth(self):
+ return self.width
+
+ def GetJoin(self):
+ return self.join
+
+ def GetCap(self):
+ return self.cap
+
+ def GetDashes(self):
+ if self.dashes is None or self.dashes is SOLID:
+ return []
+ else: return self.dashes
+
+class Brush:
+ """Brush property class."""
+ def __init__(self, bfill=Black, bpattern=None):
+ """Init the brush with the given values."""
+ self.fill = bfill
+ self.pattern = bpattern
+
+ def __str__(self):
+ return "Brush(" + str(self.fill) + ", " + str(self.pattern) + ")"
+
+ def GetColor(self):
+ return self.fill
+
+ def GetPattern(self):
+ return self.pattern
+
+class Font:
+ """Font class that accts as property object."""
+ def __init__(self, ffamily='Helvetica', fsize=12):
+ """Init the font with the given values."""
+ self.family = ffamily
+ self.size = fsize
+
+ def GetFaceName(self):
+ """Return the fontfamily the font belongs to."""
+ return self.family
+
+ def GetPointSize(self):
+ """Return the size of the font in points."""
+ return self.size
+
+# Instantiate an empty pen.
+TRANSPARENT_PEN = Pen(None, 0, None)
+# Instantiate an empty brush.
+TRANSPARENT_BRUSH = Brush(None, None)
+# Instantiate a solid pattern.
+SOLID = Pattern()
+
+class SVGMapWriterError(Exception):
+ """Get raised for problems when writing map-svg files.
+
+ Occasion when this exception is raised:
+ Two layers have the same name to be used as BaseId: Name Clash
+ """
+
+
+class SVGRenderer(BaseRenderer):
+ """Class to render a map onto a VirtualDC.
+
+ This class, derived from BaseRenderer, will render a hole
+ session onto the VirtualDC to write all shapes as SVG code
+ to a file.
+ In opposite to other renderers it includes metadata, such as
+ shape ids and classification, when rendering the shapes.
+ """
+ def __init__(self, dc, map, scale, offset, region,
+ resolution = 1.0, honor_visibility = 1):
+ """Init SVGRenderer and call superclass init."""
+ BaseRenderer.__init__(self, dc, map, scale, offset, region,
+ resolution, honor_visibility)
+ #
+ self.factor = (abs(region[2]) + abs(region[3])) / (2.0 * 1000.0)
+ self.used_baseids=[] # needed for name clash check
+
+ def make_point(self, x, y):
+ """Return a Point object from two values."""
+ return Point(x, y)
+
+ def label_font(self):
+ """Return the font object for the label layer.
+
+ As we scale stuff, the fontsize also needs to be scaled."""
+ if verbose>1:
+ log("label_font() called.\n")
+ return Font(fsize=12*self.factor)
+
+ def tools_for_property(self, prop):
+ """Return a pen/brush tuple build from a property object."""
+ fill = prop.GetFill()
+ if fill is Transparent:
+ brush = TRANSPARENT_BRUSH
+ else:
+ brush = Brush(fill, SOLID)
+
+ stroke = prop.GetLineColor()
+ if stroke is Transparent:
+ pen = TRANSPARENT_PEN
+ else:
+ pen = Pen(stroke, prop.GetLineWidth() * self.factor, SOLID)
+ return pen, brush
+
+ def draw_polygon_shape(self, layer, points, pen, brush):
+ """Draw a polygon shape from layer with the given brush and pen
+
+ The shape is given by points argument which is a the return
+ value of the shape's Points() method. The coordinates in the
+ DC's coordinate system are determined with
+ self.projected_points.
+ """
+ points = self.projected_points(layer, points)
+
+ if verbose > 1:
+ log("drawing polygon with brush %s and pen %s\n" %
+ (str(brush), str(pen)) )
+ if verbose > 2:
+ log("points: %s\n" %(repr(points)))
+
+ self.dc.SetBrush(brush)
+ self.dc.SetPen(pen)
+ self.dc.DrawPolygonPath(points)
+
+ def draw_point_shape(self, layer, points, pen, brush, size=2):
+ """Draw a point shape from layer with the given brush and pen
+
+ The shape is given by points argument which is a the return
+ value of the shape's Points() method. The coordinates in the
+ DC's coordinate system are determined with
+ self.projected_points.
+
+ The point is drawn as a circle centered on the point.
+ """
+ points = self.projected_points(layer, points)
+ if not points:
+ return
+
+ radius = self.factor * size
+ self.dc.SetBrush(brush)
+ self.dc.SetPen(pen)
+ for part in points:
+ for p in part:
+ self.dc.DrawCircle(p.x - radius, p.y - radius,
+ 2.0 * radius)
+
+ def draw_shape_layer_incrementally(self, layer):
+ """Draw a shapelayer incrementally.
+ """
+ dc = self.dc
+ brush = TRANSPARENT_BRUSH
+ pen = TRANSPARENT_PEN
+
+ value = None
+ field = None
+ lc = layer.GetClassification()
+ field = layer.GetClassificationColumn()
+ defaultGroup = lc.GetDefaultGroup()
+ table = layer.ShapeStore().Table()
+
+ if lc.GetNumGroups() == 0:
+ # There's only the default group, so we can pretend that
+ # there is no field to classifiy on which makes things
+ # faster since we don't need the attribute information at
+ # all.
+ field = None
+ if verbose > 0:
+ log("layer %s has no classification\n" % layer.Title())
+
+ # Determine which render function to use.
+ useraw, draw_func, draw_func_param = \
+ self.low_level_renderer(layer)
+ if verbose > 0 : log("Using draw_func %s\n"%(repr(draw_func)))
+
+ tool_cache = {}
+
+ new_baseid=dc.SetBaseID(layer.title)
+ if new_baseid in self.used_baseids:
+ raise SVGMapWriterError(_("Clash of layer names!\n")+ \
+ _("Two layers probably have the same name, try renaming one."))
+ # prefix of a shape id to be unique
+ self.used_baseids.append(new_baseid)
+ # Titel of current layer to the groups meta informations
+ dc.BeginGroup(meta={'Layer':layer.Title(), })
+ # Delete all MetaData
+ dc.FlushMeta()
+ for shape in self.layer_shapes(layer):
+ if field is None:
+ group = defaultGroup
+ value = group.GetDisplayText()
+ else:
+ value = table.ReadValue(shape.ShapeID(), field)
+ group = lc.FindGroup(value)
+
+ if not group.IsVisible():
+ continue
+
+ # Render classification
+ shapeType = layer.ShapeType()
+ props = group.GetProperties()
+
+ # put meta infos into DC
+ if field and value:
+ dc.SetMeta({field:value, })
+ # set current shape id
+ dc.SetID(shape.ShapeID())
+
+ try:
+ pen, brush = tool_cache[id(group)]
+ except KeyError:
+ pen, brush = tool_cache[id(group)] \
+ = self.tools_for_property(group.GetProperties())
+
+ if useraw:
+ data = shape.RawData()
+ else:
+ data = shape.Points()
+
+ if shapeType==SHAPETYPE_POINT:
+ draw_func(draw_func_param, data, pen, brush,
+ size = group.GetProperties().GetSize())
+ elif shapeType==SHAPETYPE_ARC:
+ # do not fill the polylines in linestring layers
+ draw_func(draw_func_param, data, pen, TRANSPARENT_BRUSH)
+ else:
+ draw_func(draw_func_param, data, pen, brush)
+ # compatibility
+ if 0:
+ yield True
+ # reset shape id
+ dc.SetID(-1)
+ dc.SetBaseID("")
+ dc.EndGroup()
+
+ def draw_raster_layer(self, layer):
+ """Draw the raster layer"""
+ # TODO: For now we cannot draw raster layers onto our VirtualDC
+ log(_("Warning: Raster layer not written as " +
+ "svgexport does not support this yet!\n"))
+
+ def draw_raster_data(self, data, format="BMP"):
+ """Draw the raster image in data onto the DC"""
+ # TODO: For now we cannot draw raster data onto our VirtualDC
+ pass
+
+ def RenderMap(self, selected_layer, selected_shapes):
+ """Overriden to avoid automatic rendering of legend,
+ scalbar and frame.
+ """
+ dc = self.dc
+ self.selected_layer = selected_layer
+ self.selected_shapes = selected_shapes
+ minx, miny, width, height = self.region
+ # scale down to a size of 1000
+ trans = Trafo()
+ trans.Append('scale', (1000.0 / ((width + height) / 2.0)))
+ #
+ dc.BeginClipPath('mapclip')
+ dc.DrawRectangle(0, 0, width, height)
+ dc.EndClipPath()
+ #
+ dc.BeginGroup(meta={'Object':'map', }, clipid='mapclip', \
+ transform=trans)
+ self.render_map()
+ dc.EndGroup()
+
+
+class VirtualDC(XMLWriter):
+ """This class imitates a DC and writes SVG instead.
+
+ All shapes and graphic objects will be turned into
+ SVG elements and will be written into a file.
+ Any properties, such as stroke width or stroke color,
+ will be written together with the SVG elements.
+ """
+ def __init__(self, file, dim=(0,0), units=''):
+ """Setup some variables and objects for property collection."""
+ XMLWriter.__init__(self)
+ self.dim = dim
+ self.units = units
+ self.pen = {}
+ self.brush = {}
+ self.font = {}
+ self.meta = {}
+ self.style = {}
+ # Some buffers
+ self.points = []
+ self.id = -1
+ self.flush_meta = 1
+ self.write(file)
+
+ def write_indent(self, str):
+ """Write a string to the file with the current indention level.
+ """
+ from Thuban.Model.xmlwriter import TAB
+ self.file.write("%s%s" % (TAB*self.indent_level, str))
+
+ def AddMeta(self, key, val):
+ """Append some metadata to the array that will be
+ written with the next svg-element
+ """
+ if key is '' or val is '':
+ return
+ self.meta[key] = val
+
+ def SetMeta(self, pairs, flush_after=1):
+ """Delete old meta informations and set the new ones."""
+ self.meta = {}
+ self.flush_meta = flush_after
+ for key, val in pairs.items():
+ self.AddMeta(key, val)
+
+ def FlushMeta(self):
+ """Drop collected metadata."""
+ self.meta = {}
+
+ def BeginGroup(self, **args):
+ """Begin a group of elements.
+
+ Possible arguments:
+ meta A list of key, value metadata pairs
+ style A list of key, value style attributes
+ clipid The ID of a clipPath definition to be
+ applied to this group
+ """
+ self.FlushMeta()
+ # adding meta data
+ if args.has_key('meta'):
+ for key, val in args['meta'].items():
+ self.AddMeta(key, val)
+ attribs = " "
+ # adding style attributes
+ if args.has_key('style'):
+ for key, val in args['style'].items():
+ attribs += '%s="%s" ' % (key, val)
+ # adding clip informations
+ if args.has_key("clipid"):
+ attribs += ' clip-path="url(#%s)"' % (args['clipid'],)
+ # FIXME: this shouldn't be static
+ attribs += ' clip-rule="evenodd"'
+ if args.has_key('transform'):
+ trafostr = self.parse_trafo(args['transform'])
+ if trafostr:
+ attribs += ' transform="%s"' % (trafostr)
+ # put everything together
+ self.write_indent('<g %s%s>\n' % (self.make_meta(), attribs))
+ self.indent_level += 1
+
+ def parse_trafo(self, trafo):
+ """Examine a trafo object for asigned transformations details."""
+ if not trafo:
+ return ''
+ retval = ''
+ while trafo.Count() > 0:
+ trans, coeffs = tuple(trafo.Pop())
+ if isinstance(coeffs, ListType):
+ retval += " %s%s" % (trans, join(coeffs, ', '))
+ else: retval += " %s(%s)" % (trans, coeffs)
+ # return the string
+ return retval
+
+ def EndGroup(self):
+ """End a group of elements"""
+ self.indent_level -= 1
+ self.write_indent('</g>\n')
+ self.FlushMeta()
+
+ def BeginExport(self):
+ """Start the export process and write basic document
+ informations to the file.
+ """
+ self.write_indent('<?xml version="1.0" encoding="ISO-8859-1" '
+ 'standalone="yes"?>\n')
+ width, height = self.dim
+ self.write_indent('<svg>\n')
+ self.indent_level += 1
+
+ def EndExport(self):
+ """End the export process with closing the SVG tag and close
+ the file accessor"""
+ self.indent_level -= 1
+ self.write_indent('</svg>\n')
+ self.close()
+
+ def Close(self):
+ """Close the file."""
+ self.close()
+
+ def BeginDrawing(self):
+ """Dummy function to work with the Thuban renderers."""
+ pass
+
+ def EndDrawing(self):
+ """Dummy function to work with the Thuban renderers."""
+ pass
+
+ def GetSizeTuple(self):
+ """Return the dimension of this virtual canvas."""
+ return self.dim
+
+ def GetTextExtent(self, text):
+ """Return the dimension of the given text."""
+ # FIXME: find something more appropriate
+ try:
+ if self.font:
+ return (int(self.font["font-size"]),
+ len(text) * int(self.font["font-size"]))
+ else: return (12,len(text) * 10)
+ except ValueError:
+ return (12,len(text) * 10)
+
+
+ def SetBaseID(self, id):
+ """Set first part of ID stored by the svg elements. Return it.
+
+ Will be used in make_id() as first part of an XML attribute "id".
+ The second part is set by SetID().
+ Check comments at make_id().
+
+ We might add an abritrary "t" for thuban if the parameter
+ starts with XML, which is not allowed in XML 1.0.
+
+ We need to ensure that all characters are okay as XML id attribute.
+ As there seem no easy way in Python (today 20040925) to check
+ for compliance with XML 1.0 character classes like NameChar,
+ we use Python's string method isalnum() as approximation.
+ (See http://mail.python.org/pipermail/xml-sig/2002-January/006981.html
+ and xmlgenchar.py. To be better we would need to hold our own
+ huge table of allowed unicode characters.
+ FIXME if python comes with a better funcation for XML 1.0 NameChar)
+
+ Characters that are not in our approx of NameChar get transformed
+ get escaped to their hex value.
+ """
+ # an ID Name shall not start with xml.
+ if id[0:3].lower() == "xml":
+ id = "t" + id
+
+ self.baseid = ""
+ for c in id:
+ if c.isalnum() or c in ".-_":
+ self.baseid += c
+ else:
+ self.baseid += binascii.b2a_hex(c)
+ return self.baseid
+
+ def SetID(self, id):
+ """Set second part of ID stored by the svg elements.
+
+ Will be used in make_id() as first part of an XML attribute "id".
+ Only set this to positive integer numbers.
+ Read comments at SetBaseID() and make_id().
+ """
+ self.id = id
+
+ def SetFont(self, font):
+ """Set the fontproperties to use with text elements."""
+ if font is not None:
+ fontname = font.GetFaceName()
+ size = font.GetPointSize()
+ for svgfont, pattern in fontMap.items():
+ if pattern.match(fontname):
+ fontname = svgfont
+ break
+ if fontname:
+ self.font["font-family"] = fontname
+ else: self.font["font-family"] = None
+ if size:
+ self.font["font-size"] = str(size)
+ else: self.font["font-size"] = None
+
+ def SetPen(self, pen):
+ """Set the style of the pen used to draw graphics."""
+ if pen is TRANSPARENT_PEN:
+ self.pen = {}
+ else:
+ self.pen["stroke"] = pen.GetColor().hex()
+ self.pen["stroke-dasharray"] = join(pen.GetDashes(), ',')
+ self.pen["stroke-width"] = pen.GetWidth()
+ self.pen["stroke-linejoin"] = svg_joins[pen.GetJoin()]
+ self.pen["stroke-linecap"] = svg_caps[pen.GetCap()]
+
+ def SetBrush(self, brush):
+ """Set the fill properties."""
+ if brush is TRANSPARENT_BRUSH:
+ self.brush['fill'] = 'none'
+ elif brush.GetPattern() is SOLID:
+ self.brush['fill'] = brush.GetColor().hex()
+ else: # TODO Handle Patterns
+ pass
+
+ def SetTextForeground(self, color):
+ """Set the color of the text foreground."""
+ self.font['fill'] = color.hex()
+
+ def make_style(self, line=0, fill=0, font=0):
+ """Build the style attribute including desired properties
+ such as fill, forground, stroke, etc."""
+ result = []
+ # little helper function
+ def append(pairs):
+ for key, val in pairs.items():
+ if not val in [None, '']:
+ result.append('%s:%s' % (key, val))
+ #
+ if line and len(self.pen) > 0:
+ append(self.pen)
+ if fill and len(self.brush) > 0:
+ append(self.brush)
+ if font and len(self.font) > 0:
+ append(self.font)
+ style = join(result, '; ')
+ if style:
+ return 'style="%s"' % (style, )
+ else:
+ return ''
+
+ def make_meta(self, meta=None):
+ """Build the meta attribute."""
+ result = []
+ if not meta:
+ meta = self.meta
+ if len(meta) is 0:
+ return ''
+ for key, val in meta.items():
+ if not val in [None, '', 'none']:
+ result.append('%s:%s' % (key, val))
+ if self.flush_meta:
+ self.meta = {}
+ return 'meta="%s"' % (join(result, '; '))
+
+ def make_id(self):
+ """Return id= string for object out of currently set baseid and id.
+
+ Return the empty string if no id was set.
+
+ In an XML file each id should be unique
+ (see XML 1.0 section 3.3.1 Attribute Types, Validity constraint: ID)
+ So this function should only return a unique values.
+ which also coforms to the the XML "Name production" (section 3.2).
+
+ For this it completely depends
+ on what has been set by SetBaseID() and SetID().
+ Only call this function if you have called them w unique values before
+ (or negative x in SetID(x) to get an empty result)
+ Will raise SVGMapWriterError if SetID value cannot be converted to %d.
+
+ A check of uniqueness in this function might be time consuming,
+ because it would require to hold and search through a complete table.
+ """
+ if self.id < 0:
+ return ''
+ try:
+ id= 'id="%s_%d"' % (self.baseid, self.id)
+ except TypeError, inst:
+ raise SVGMapWriterError(_("Internal make_id() failure: ") \
+ + repr(inst))
+ return id
+
+ def DrawEllipse(self, x, y, dx, dy):
+ """Draw an ellipse."""
+ elips = '<ellipse cx="%s" cy="%s" rx="%s" ry="%s" %s %s %s/>\n'
+ self.write_indent(elips % (x, y, dx, dy, self.make_id(),
+ self.make_style(1,1,0), self.make_meta()) )
+
+ def DrawCircle(self, x, y, radius):
+ """Draw a circle onto the virtual dc."""
+ self.write_indent('<circle cx="%s" cy="%s" r="%s" %s %s %s/>\n' %
+ (x, y, radius, self.make_id(), self.make_style(1,1,0),
+ self.make_meta()) )
+
+ def DrawRectangle(self, x, y, width, height):
+ """Draw a rectangle with the given parameters."""
+ rect = '<rect x="%s" y="%s" width="%s" height="%s" %s %s %s/>\n'
+ self.write_indent(rect % ( x, y, width, height, self.make_id(),
+ self.make_style(1,1,0), self.make_meta()) )
+
+ def DrawText(self, text, x, y):
+ """Draw Text at the given position."""
+ beginText = '<text x="%s" y="%s" %s %s %s>'
+ self.write_indent(beginText % ( x, y, self.make_id(),
+ self.make_style(0,0,1), self.make_meta()) )
+ self.file.write(escape(text))
+ self.file.write('</text>\n')
+
+ def DrawLines(self, points):
+ """Draw some points into a Buffer that will be
+ written before the next object.
+ """
+ self.DrawPolygonPath([points], closed=False)
+
+ def DrawPolygonPath(self, polys, closed=True):
+ """Draw a list of polygons or polylines as one SVG path.
+
+ Parameter:
+ polys list of poly- gons/lines; each consisting of a list of points
+ closed Boolean; optional; Default: True
+ False will leave each subpath open thus making it polylines.
+ """
+ self.write_indent('<path %s ' % (self.make_style(1,1,0)))
+ data = []
+ for poly in polys:
+ i = 0
+ for point in poly:
+ if i is 0:
+ data.append('\nM %s %s' % (point.x, point.y))
+ i+=1
+ else:
+ # SVG 1.1 Spec 8.3.1 recommends that lines length <= 255
+ # we make a best effort in throwing in a few newlines
+ data.append('\nL %s %s' % (point.x, point.y))
+ if closed:
+ data.append(' Z')
+
+ # Put everything together and write it to the file
+ self.file.write('%s %s d="%s"/>\n' % (self.make_id(),
+ self.make_meta(), join(data, '') ) )
+
+ def DrawSpline(self, points, closed=0):
+ """Calculate square bezier points for an xfig approximated spline.
+
+ DrawSpline() needs to do the same as the function of the Device Context
+ of wxWidgets. Code inspection shows it uses the "approximated
+ splines" of xfig <= 3.1. This can be mapped
+ on SVG's squared bezier curves,
+ by doing the same calculation like wxPostScriptDC::DoDrawSpline() in
+ wxWidgets src/generic/dcpsg.cpp.
+ Which is derived from xfig's 3.1.4 u_draw.c(draw_open_spline()).
+
+ And then leave out the last translation to cubic beziers
+ done in the postscript code of DrawSplineSection.
+ """
+ self.write_indent('<path %s ' % (self.make_style(1,1,0)))
+ datastr = ""
+
+ x1=points[0].x
+ y1=points[0].y
+
+ datastr+=('M %s %s ' % (x1, y1))
+
+ c=points[1].x
+ d=points[1].y
+
+ x3 = (x1 + c) / 2;
+ y3 = (y1 + d) / 2;
+
+ datastr+=('L %s %s ' % (x3,y3))
+
+ for point in points[2:]:
+ x2 = c
+ y2 = d
+ c = point.x
+ d = point.y
+ x3 = (x2 + c) / 2;
+ y3 = (y2 + d) / 2;
+
+ # With SVG's bezier commands, the last point becomes the next start
+ # so no new L necessary
+ # SVG Spec 1.1 recommends to not uses lines longer than 255 chars
+ datastr+=('Q %s %s %s %s\n' % (x2,y2,x3,y3))
+
+ datastr+=('L %s %s' % (c,d))
+
+ self.file.write('%s %s d="%s"/>\n' % (self.make_id(),
+ self.make_meta(), datastr ) )
+
+ def BeginClipPath(self, id):
+ """Build a clipping region to draw in."""
+ self.write_indent('<clipPath id="%s">\n' % id)
+ self.indent_level += 1
+
+ def EndClipPath(self):
+ """End a clip path."""
+ self.indent_level -= 1
+ self.write_indent("</clipPath>\n")
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/svgsaver.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/svgsaver.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/svgsaver.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,105 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Markus Rechtien <markus at intevation.de> (2004)
+# Bernhard Herzog <bh at intevation.de> (2004)
+# Bernhard Reiter <bernhard at intevation.de> (2004)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2721 $"
+# $Source$
+# $Id: svgsaver.py 2721 2007-01-13 15:11:42Z dpinte $
+
+
+"""
+Classes to write a session in SVG format
+"""
+
+
+# Needed wx.-toolkit classes
+import wx
+
+# We need os.path
+import os
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Import SVG related classes
+from svgmapwriter import VirtualDC, SVGRenderer, SVGMapWriterError
+
+
+def write_to_svg(context):
+ '''Export data depending on the set properties.
+
+ This is the main export funcation.
+ '''
+ canvas = context.mainwindow.canvas
+ file = None
+ map = canvas.Map()
+
+ if hasattr(canvas, "export_path"):
+ export_path = canvas.export_path
+ else:
+ export_path="."
+ # Get the file the session shall be written to
+ dlg = wx.FileDialog(canvas, _("Write SVG"), export_path, "",
+ "Scalable Vector Graphics (*.svg)|*.svg",
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+
+ response = dlg.ShowModal()
+ if response == wx.ID_OK:
+ file = dlg.GetPath()
+ else: # Do nothing if choice was interrupted.
+ return 0
+
+ # If the user selected a file
+ if file and map is not None:
+ canvas.export_path = os.path.dirname(file)
+ # Initialize some dimensions and calculate the map bounds
+ width, height = canvas.GetSizeTuple()
+ llx, lly = canvas.win_to_proj(0, height)
+ urx, ury = canvas.win_to_proj(width, 0)
+ mapwidth, mapheight = ((urx - llx), (ury - lly))
+ mapregion = (llx, lly, mapwidth, mapheight)
+
+ # Get all selected layers and shapes that should be written as SVG
+ selected_layer = canvas.selection.SelectedLayer()
+ selected_shapes = canvas.selection.SelectedShapes()
+ try:
+ dc = VirtualDC(file, (mapwidth, mapheight, ))
+ dc.BeginExport()
+ # map scale offset region
+ renderer = SVGRenderer(dc, map, 1.0, (0 - min(llx, urx),
+ 0 + max(lly, ury)), mapregion)
+ # Render the map
+ renderer.RenderMap(selected_layer, selected_shapes)
+ dc.EndExport()
+ except SVGMapWriterError, inst:
+ context.mainwindow.RunMessageBox(_("Error: SVG not written!"),
+ text=_("Could not write SVG because: ")+ str(inst),
+ flags= wx.OK | wx.ICON_HAND)
+ # delete partly writting file
+ os.remove(file)
+
+
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+# See Thuban/UI/menu.py for the API of the Menu class
+from Thuban.UI.mainwindow import main_menu
+
+# create a new command and register it
+registry.Add(Command('write_to_svg', _('Write SVG Map'), write_to_svg,
+ helptext = _('Export the a map into a SVG file')))
+
+# find the menu we want to be in (create it anew if not found)
+menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))
+
+# finally bind the new command with an entry in the extensions menu
+menu.InsertItem('write_to_svg')
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/test/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/test/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/test/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/test/test_svgmapwriter.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/test/test_svgmapwriter.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/test/test_svgmapwriter.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,482 @@
+# Copyright (c) 2004,2005 by Intevation GmbH
+# Authors:
+# Markus Rechtien <markus at intevation.de> (2004)
+# Bernhard Reiter <bernhard at intevation.de> (2004,2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Test the svgexport."""
+
+__version__ = "$Revision: 2671 $"
+# $Source$
+# $Id: test_svgmapwriter.py 2671 2005-10-17 20:10:18Z bernhard $
+
+
+import os
+import sys
+import string
+import StringIO
+import unittest
+
+# If run directly as a script, add Thuban's test directory to the path.
+# Otherwise we assume that the importing code has already done it.
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),
+ "..", "..", "..", "test"))
+from mockgeo import SimpleShapeStore
+import support
+support.initthuban()
+
+# Now import needed SVG stuff
+from Extensions.svgexport.svgmapwriter import VirtualDC, \
+ Pen, Brush, SOLID, Point, Font, TRANSPARENT_PEN, TRANSPARENT_BRUSH, \
+ SVGRenderer, SVGMapWriterError
+# Color related classes from the model of thuban
+from Thuban.Model.color import Color, Black, Transparent
+
+from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POLYGON
+from Thuban.Model.map import Map
+from Thuban.Model.layer import BaseLayer, Layer
+from Thuban.Model.table import MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
+
+
+
+# We use xmlsupport to verify the SVG output
+import xmlsupport
+
+class BaseTestWithDC(unittest.TestCase):
+ """Add dc creation and self.to_destroy list to setUp() and tearDown().
+
+ This is a baseclass for tests needing a dc.
+ """
+ def setUp(self):
+ """Create dc for testing and set up self.to_destroy.
+
+ Test should put all objects whose Destroy
+ should be called at unittest.main
+ the end into this list so that they're destroyed in tearDown
+ """
+ self.to_destroy = []
+
+ self.file = StringIO.StringIO()
+ self.dc = VirtualDC(self.file)
+
+ def tearDown(self):
+ for obj in self.to_destroy:
+ obj.Destroy()
+
+
+class BaseTestWithDCtools(BaseTestWithDC):
+ """Add standard colors and polygon to setUp() for DC tests."""
+ def setUp(self):
+ """Initialize tools."""
+ BaseTestWithDC.setUp(self)
+ self.black = Black
+ self.solid_pen = Pen(Color(1.0, 0.0, 1.0), 3, SOLID)
+ self.trans_pen = TRANSPARENT_PEN
+ self.solid_brush = Brush(Color(0.0, 1.0, 0.0), SOLID)
+ self.trans_brush = TRANSPARENT_BRUSH
+ self.polygon = [Point(5.6,5.5), Point(95.4,5.3), Point(95.2,95.1),
+ Point(5.0,95.0), Point(5.0,5.0)]
+ self.meta = {"Object":"test", "Label":"nothing"}
+ self.font = Font("Helvetica", 12)
+
+
+class TestVirtualDC(BaseTestWithDCtools):
+ '''Test VirtualDC imitating a wxDC and writing SVGRenderer instead.'''
+
+ def test_clippath(self):
+ '''Define a clipping region and close it afterwards.'''
+ data = '<clipPath id="testid">\n</clipPath>'
+ self.dc.BeginClipPath('testid')
+ self.dc.EndClipPath()
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_polygon_closed(self):
+ '''Set drawing properties and draw a polygon onto the dc.'''
+ data = ('<path style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:#00ff00" '
+ 'meta="Object:test; Label:nothing" d="\nM 5.6 5.5 '
+ 'L 95.4 5.3 L 95.2 95.1 L 5.0 95.0 L 5.0 5.0 Z"/>')
+ dc = self.dc
+ dc.SetPen(self.solid_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.solid_brush)
+ dc.DrawPolygonPath([self.polygon])
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_polyline(self):
+ '''Set drawing properties and draw a polyline onto the dc.'''
+ data = ('<path style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:#00ff00" '
+ 'meta="Object:test; Label:nothing" d="\nM 5.6 5.5'
+ '\nL 95.4 5.3\nL 95.2 95.1\nL 5.0 95.0\nL 5.0 5.0"/>')
+ dc = self.dc
+ dc.SetPen(self.solid_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.solid_brush)
+ dc.DrawPolygonPath([self.polygon], closed=False)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_transparent_polyline(self):
+ '''Test dc drawing a transparent polyline.'''
+ data = ('<path style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:none" '
+ 'meta="Object:test; Label:nothing" d="\nM 5.6 5.5'
+ ' L 95.4 5.3\nL 95.2 95.1\nL 5.0 95.0\nL 5.0 5.0"/>')
+ dc = self.dc
+ dc.SetPen(self.solid_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.trans_brush)
+ dc.DrawPolygonPath([self.polygon], closed=False)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_polygon_with_hole(self):
+ '''Set drawing properties and draw a polygon onto the dc.'''
+
+ holepolygon = [Point(11.1,11.1), Point(33.3,11.1), Point(22.2,22.2),
+ Point(11.1,11.1)]
+ data = ('<path style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:#00ff00" '
+ 'meta="Object:test; Label:nothing" d="\nM 5.6 5.5 '
+ 'L 95.4 5.3 L 95.2 95.1 L 5.0 95.0 L 5.0 5.0 Z'
+ '\nM 11.1 11.1 L 33.3 11.1 L 22.2 22.2 L 11.1 11.1 Z"/>')
+
+ dc = self.dc
+ dc.SetPen(self.solid_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.solid_brush)
+ dc.DrawPolygonPath([self.polygon, holepolygon])
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_rect(self):
+ '''Set drawing properties and draw a rectangle'''
+ data = ('<rect x="5.5" y="5.4" width="90.3" height="90.2" '
+ 'style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:none" '
+ 'meta="Object:test; Label:nothing"/>')
+ dc = self.dc
+ dc.SetPen(self.solid_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.trans_brush)
+ dc.DrawRectangle(5.5, 5.4, 90.3, 90.2)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_circle(self):
+ '''Set drawing properties and draw a circle'''
+ data = ('<circle cx="5.5" cy="5.3" r="90.1" style="'
+ 'fill:#00ff00" meta="Object:test; Label:nothing"/>')
+ dc = self.dc
+ dc.SetPen(self.trans_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.solid_brush)
+ dc.DrawCircle(5.5, 5.3, 90.1)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_ellipse(self):
+ '''Set drawing properties and draw a circle'''
+ data = ('<ellipse cx="5.5" cy="5.3" rx="90.1" ry="100.321" style="'
+ 'fill:#00ff00" meta="Object:test; Label:nothing"/>')
+ dc = self.dc
+ dc.SetPen(self.trans_pen)
+ dc.SetMeta(self.meta)
+ dc.SetBrush(self.solid_brush)
+ dc.DrawEllipse(5.5, 5.3, 90.1, 100.321)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_text(self):
+ '''Set drawing properties and draw a circle'''
+ data = ('<text x="123.321" y="1515.5151" style="font-size:12; '
+ 'font-family:Helvetica; fill:#000000" >Some text.</text>')
+ dc = self.dc
+ dc.SetTextForeground(self.black)
+ dc.SetFont(self.font)
+ dc.DrawText('Some text.', 123.321, 1515.5151)
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+ def test_document(self):
+ '''Set up a document with a dimension and
+ latin encoding'''
+ data = ('<?xml version="1.0" encoding="ISO-8859-1" standalone'
+ '="yes"?>\n<svg>\n</svg>')
+ self.dc.BeginExport()
+ self.dc.EndExport()
+ self.assertEquals(xmlsupport.sax_eventlist(data=data),
+ xmlsupport.sax_eventlist(data=self.file.getvalue()))
+
+class TestDrawSplines(BaseTestWithDCtools):
+ """Testing DrawSpline variations.
+ See comments in DrawSpline().
+ """
+
+ def setUp(self):
+ BaseTestWithDCtools.setUp(self)
+ self.dataframe = ('<path style="stroke-linejoin:round; stroke:#ff00ff; '
+ 'stroke-width:3; stroke-linecap:round; fill:none" '
+ 'meta="Object:test; Label:nothing" d="%s"/>')
+
+ self.file = StringIO.StringIO()
+ self.dc = VirtualDC(self.file)
+ self.dc.SetPen(self.solid_pen)
+ self.dc.SetMeta(self.meta)
+ self.dc.SetBrush(self.trans_brush)
+
+ def test_drawspline3(self):
+ '''Test DrawSpline with three points in a row.'''
+
+ d=('M 10 10 L 12.55 12.55 Q 15.1 15.1 17.65 17.65\nL 20.2 20.2')
+ data=(self.dataframe % d)
+
+ self.dc.DrawSpline([ Point(10, 10),
+ Point(15.1, 15.1),
+ Point(20.2, 20.2) ])
+ #print file.getvalue()
+ self.assertEquals(xmlsupport.sax_eventlist(data = data),
+ xmlsupport.sax_eventlist(data = self.file.getvalue()))
+
+ def test_drawspline4(self):
+ '''Test DrawSpline with four points in a row.'''
+
+ d='M 0 0 L 0 1 Q 0 2 0 3\nQ 0 4 0 5\nL 0 6'
+ data=(self.dataframe % d)
+
+ self.dc.DrawSpline([ Point(0, 0),
+ Point(0, 2),
+ Point(0, 4),
+ Point(0, 6) ])
+ #print file.getvalue()
+ self.assertEquals(xmlsupport.sax_eventlist(data = data),
+ xmlsupport.sax_eventlist(data = self.file.getvalue()))
+
+
+
+class TestSVGRendererIDHandling(BaseTestWithDC):
+
+ def test_make_id_nonintegersetid(self):
+ """Test that exception is raised when SetID was called with chars."""
+ dc=self.dc
+ dc.SetBaseID("a")
+ dc.SetID("abc")
+ self.assertRaises(SVGMapWriterError, dc.make_id)
+
+ def test_make_ide_nosetbaseid(self):
+ """Test as no setbaseid results in valid XML id starting with '_'."""
+ dc=self.dc
+ dc.SetBaseID("")
+ dc.SetID(123)
+ id=dc.make_id() # returns 'id="xxxxxx"'
+ self.assert_(id[4]=='_' or (id[4] in string.ascii_letters))
+
+ def test_xml_id_constraints(self):
+ """Test the checks for the XML id contraints by trying bad id parts."""
+
+ dc=self.dc
+ dc.SetID(42)
+
+ # an xml Name shall better not start with "xml" (case insensitive)
+ dc.SetBaseID("xml")
+ id=dc.make_id() # returns 'id="xxxxxx"'
+ self.assert_(id[4:7].lower() != "xml")
+
+ dc.SetBaseID("XmL")
+ id=dc.make_id()
+ self.assert_(id[4:7].lower() != "xml")
+
+ # recommended to better not use ":"
+ dc.SetBaseID("abc:def")
+ id=dc.make_id()
+ self.assert_(":" not in id )
+
+ # an XML name shall only have:
+ # Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
+ dc.SetBaseID("abc def")
+ id=dc.make_id()
+ self.assert_(" " not in id )
+
+ dc.SetBaseID("ab!cd")
+ id=dc.make_id()
+ self.assert_("!" not in id )
+
+ dc.SetBaseID("a.b-c_d")
+ id=dc.make_id()
+ self.assert_(id[4:11]=="a.b-c_d")
+
+
+ def test_make_id(self):
+ """Check "layer" and "layer1" do not clash; given integer ShapeIDs.
+ """
+ dc=self.dc
+ dc.SetBaseID("layer")
+ dc.SetID(10)
+ id1=dc.make_id()
+ dc.SetBaseID("layer1")
+ dc.SetID(0)
+ id2=dc.make_id()
+
+ self.assertNotEqual(id1,id2)
+
+
+ def test_check_for_layer_name_clash(self):
+ '''Create 2 layers with same name, try to write and check exception.
+ '''
+
+ # BaseLayer is not enough, because BaseRenderer.render_map()
+ # checks on isinstance of Layer not BaseLayer.
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (10, 10)]]]
+ store = SimpleShapeStore(SHAPETYPE_ARC, shapes, table)
+
+ map = Map("TestLayerNameClash")
+ self.to_destroy.append(map)
+ layer=Layer("Same Name", store)
+ map.AddLayer(layer)
+ # reusing the same store with the same table and shapes should be okay
+ layer=Layer("Same Name", store)
+ map.AddLayer(layer)
+
+ renderer = SVGRenderer(self.dc, map,
+ scale=1.0, offset=(0,0), region=(0,0,10,10))
+
+ self.assertRaises(SVGMapWriterError,
+ renderer.RenderMap, None, None)
+
+class TestSVGRenderer(BaseTestWithDC):
+ """Test methods of SVGRenderer."""
+
+ def test_label_font(self):
+ """Test that label_font used the self.factor."""
+ mockmap = Map("mock title")
+ self.to_destroy.append(mockmap)
+ renderer = SVGRenderer(self.dc, mockmap,
+ scale=1.0, offset=(0,0), region=(0,0,30000,30000))
+ #print renderer.factor
+ self.assertEqual( renderer.label_font().GetPointSize(),
+ 12*renderer.factor
+ )
+
+class Testobjectexport(BaseTestWithDC):
+
+ def test_transparent_polygon(self):
+ """Create layer with non-filled polygon and test svg rendering."""
+
+ data = ('<clipPath id="mapclip">\n'
+ ' <rect x="0" y="0" width="10" height="10" />\n'
+ '</clipPath>\n'
+ '<g meta="Object:map" clip-path="url(#mapclip)" '
+ 'clip-rule="evenodd" transform=" scale(100.0)">\n'
+ ' <g meta="Layer:P-Layer" >\n'
+ ' <path style="stroke-linejoin:round; stroke:#000000; '
+ 'stroke-width:0.01; stroke-linecap:round; fill:none" '
+ 'id="P-Layer_0"'
+ ' d="\nM 0.0 0.0\nL 10.0 -10.0\nL 0.0 -10.0\nL 0.0 0.0 Z"/>\n'
+ ' </g>\n</g>\n')
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (10, 10), (0, 10), (0, 0) ]]]
+ store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
+
+ map = Map("testpolygonexport")
+ self.to_destroy.append(map)
+ layer=Layer("P-Layer", store, fill=Transparent)
+ map.AddLayer(layer)
+
+ renderer = SVGRenderer(self.dc, map,
+ scale=1.0, offset=(0,0), region=(0,0,10,10))
+ renderer.RenderMap(None, None)
+ #print (data)
+ #print (self.dc.file.getvalue())
+ self.assertEquals(data, self.dc.file.getvalue())
+
+ def test_export_polygon_with_hole(self):
+ """ Create layer with polygon ans hole and test svg rendering."""
+
+ data = ('<clipPath id="mapclip">\n'
+ ' <rect x="0" y="0" width="10" height="10" />\n'
+ '</clipPath>\n'
+ '<g meta="Object:map" clip-path="url(#mapclip)" '
+ 'clip-rule="evenodd" transform=" scale(100.0)">\n'
+ ' <g meta="Layer:P-Layer" >\n'
+ ' <path style="stroke-linejoin:round; stroke:#000000; '
+ 'stroke-width:0.01; stroke-linecap:round; fill:none" '
+ 'id="P-Layer_0"'
+ ' d="\nM 0.0 0.0\nL 0.0 -10.0\nL 10.0 -10.0\nL 0.0 0.0 Z'
+ '\nM 5.0 -6.0\nL 5.0 -7.0\nL 4.0 -7.0\nL 4.0 -6.0'
+ '\nL 5.0 -6.0 Z"/>\n'
+ ' </g>\n</g>\n')
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (0, 10), (10, 10), (0, 0) ],
+ [(5, 6), (5, 7), ( 4, 7), (4, 6), (5, 6)]
+ ]]
+ store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
+
+ map = Map("testpolygonexport")
+ self.to_destroy.append(map)
+ layer=Layer("P-Layer", store, fill=Transparent)
+ map.AddLayer(layer)
+
+ renderer = SVGRenderer(self.dc, map,
+ scale=1.0, offset=(0,0), region=(0,0,10,10))
+ renderer.RenderMap(None, None)
+ #print (data)
+ #print (self.dc.file.getvalue())
+ self.assertEquals(data, self.dc.file.getvalue())
+
+ def test_export_arc_no_fill(self):
+ """Create layer with a linestring and test svg rendering.
+
+ Even when the layer or the classifications have a fill color,
+ the resulting path shall not be filled for an ARC (linestring) layer.
+ """
+
+ data = ('<clipPath id="mapclip">\n'
+ ' <rect x="0" y="0" width="10" height="10" />\n'
+ '</clipPath>\n'
+ '<g meta="Object:map" clip-path="url(#mapclip)" '
+ 'clip-rule="evenodd" transform=" scale(100.0)">\n'
+ ' <g meta="Layer:A-Layer" >\n'
+ ' <path style="stroke-linejoin:round; stroke:#000000; '
+ 'stroke-width:0.01; stroke-linecap:round; fill:none" '
+ 'id="A-Layer_0"'
+ ' d="\nM 0.0 0.0\nL 2.0 -8.0\nL 10.0 -10.0"/>\n'
+ ' </g>\n</g>\n')
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (2, 8), (10, 10) ]]]
+ store = SimpleShapeStore(SHAPETYPE_ARC, shapes, table)
+
+ map = Map("testarcexport")
+ self.to_destroy.append(map)
+ layer=Layer("A-Layer", store, fill=Black)
+ map.AddLayer(layer)
+
+ renderer = SVGRenderer(self.dc, map,
+ scale=1.0, offset=(0,0), region=(0,0,10,10))
+ renderer.RenderMap(None, None)
+ #print (data)
+ #print (self.dc.file.getvalue())
+ self.assertEquals(data, self.dc.file.getvalue())
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/Extensions/svgexport/x.diff
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/svgexport/x.diff 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/svgexport/x.diff 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,52 @@
+Index: svgmapwriter.py
+===================================================================
+--- svgmapwriter.py (Revision 2721)
++++ svgmapwriter.py (Arbeitskopie)
+@@ -326,11 +326,11 @@
+ data = shape.Points()
+
+ if shapeType==SHAPETYPE_POINT:
+- draw_func(draw_func_param, data, pen, brush,
++ draw_func(draw_func_param, data, pen, brush,
+ size = group.GetProperties().GetSize())
+ elif shapeType==SHAPETYPE_ARC:
+- # do not fill the polylines in linestring layers
+- draw_func(draw_func_param, data, pen, TRANSPARENT_BRUSH)
++ # do not fill the polylines in linestring layers
++ draw_func(draw_func_param, data, pen, TRANSPARENT_BRUSH)
+ else:
+ draw_func(draw_func_param, data, pen, brush)
+ # compatibility
+@@ -380,7 +380,7 @@
+ All shapes and graphic objects will be turned into
+ SVG elements and will be written into a file.
+ Any properties, such as stroke width or stroke color,
+- will be written together with the SVG elementents.
++ will be written together with the SVG elements.
+ """
+ def __init__(self, file, dim=(0,0), units=''):
+ """Setup some variables and objects for property collection."""
+Index: TODO
+===================================================================
+--- TODO (Revision 2726)
++++ TODO (Arbeitskopie)
+@@ -4,6 +4,19 @@
+
+ * Enable Raster file export.
+
++Spec REC-SVG11-20030114 includes no indication about embedding raster images.
++Thus we probably have to write extra files.
++
++ Substeps:
++ a) write shown raster file as .png, no matter which
++ filename.
++ b) add filename construction based on used svg file.
++ (There can be several raster layers.)
++ c) add <image> tag to .svg file
++ Open Questions:
++ q1) What resolution to use for the PNG file?
++ q2) Should be there one PNG file or is tiling better?
++
+ For 1.0.x, x>2:
+
+ * find out why the memory shapes in class Testobjectexport
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,103 @@
+
+UMN MapServer Extension for Thuban
+===================================
+
+ *** ATTENTION: ***
+
+ The installation instructions here are detailed, so I hope everybody
+ can install the extension. People who are experienced will know
+ most of the commands, but everybody should be able to use
+ this extension.
+
+
+
+Summary
+--------------------
+
+This extension for Thuban allows you to handle UMN MapServer .map-files.
+
+
+
+Requirements
+--------------------
+
+To use the UMN MapServer extension you need:
+
+ UMN MapServer python-mapscript
+
+The extension was tested with UMN MapServer 4.0 and 4.2,
+older versions may not work.
+
+
+
+Installation
+--------------------
+
+1. You need to build and install python-mapscript if you haven't installed yet.
+
+ Download the UMN MapServer (http://mapserver.gis.umn.edu/dload.html)
+ or use one on your system. The mapscript is included in the source package.
+
+ Unpack and compile the UMN MapServer and use the following optional
+ parameters:
+
+ proj: include projection support
+ gdal: include raster support
+ tiff: include tiff support
+
+ In some cases gdal is not necessary and mapscript can install without
+ gdal support.
+ A detailed install instruction can be found on the UMN MapServer Homepage.
+ (http://mapserver.gis.umn.edu)
+
+ Go to the directory where the UMN MapServer source code tar-ball exists:
+
+ tar -zxf mapserver-4.2.0.tar.gz
+
+ Go to the new created directory:
+
+ cd mapserver-4.2.0
+
+ Configure an make the UMN MapServer
+
+ ./configure --with-gdal --with-proj --with-tiff
+ make
+
+ Now we can compile and install the python mapscript
+
+ cd mapscript/python/
+ python setup.py build
+
+ Some warnings are ok during the build of python mapscript
+
+ At last we either install mapscript as root:
+
+ python setup.py install
+
+ or (if you don't want to pollute your system with circumventing
+ the package installation system) you may set something
+ like this (not that the exact path depends on your system and
+ where you place the mapserver sources) for testing the stuff
+ temporarily:
+
+ export PYTHONPATH=~/mapserver-4.2.0/mapscript/python/build/lib.linux-i686-2.3
+
+2. Add the umn_mapserver extension import statements to ~/.thuban/thubanstart.py
+ if you run thuban directly from the source directory the statement is:
+
+ import Extensions.umn_mapserver.mf_import
+ import Extensions.umn_mapserver.mf_export
+ import Extensions.umn_mapserver.mf_handle
+
+ More about how to use an extension
+ see README in thuban/Examples/simple_extensions.
+
+3. Start Thuban and use the extension.
+
+
+
+Usage
+--------------------
+
+The usage of the extension is very intuitive, so you will see what you can do
+while you are using the extension ;)
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,33 @@
+# -*- coding:latin1 -*-
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de> (2004)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# first try out whether we can import the required module
+# of UMN MapServer MapScript.
+ok = True
+try:
+ import mapscript
+except:
+ print "Problems with UMN MapServer MapScript (not installed?)"
+ ok = False
+
+if ok:
+ import mf_import
+ import mf_export
+ import mf_handle
+
+ from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+ from Thuban import _, internal_from_unicode
+
+ ext_registry.add(ExtensionDesc(
+ name = 'UMN MapServer Management',
+ version = '1.0.0',
+ authors= [ internal_from_unicode(u'Jan Sch\xfcngel') ],
+ copyright = '2004 Intevation GmbH',
+ desc = _("Provide management methods for UMN MapServer\n" \
+ ".map-files. These can be created/imported/modified.")))
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mapfile.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mapfile.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mapfile.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1460 @@
+# -*- coding:latin1 -*-
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes to represent '.map'-file Objects.
+
+The following Classes, which are implemented in
+mapscript are not implemented yet in this extension:
+
+ DBFInfo, errorObj, fontSetObj, graticuleObj, imageObj, itemObj,
+ labelCacheMemberObj, labelCacheObj,
+ markerCacheMembet, msTiledSHPLayerInfo, queryMapObj,
+ referenzMapObj, resultCacheMemberObj, resultCacheObj,
+ shapefileObj, shapeObj, VectorObj
+
+the following are only used to create a necessary object. They are not
+realy created as a MF_Object.
+
+ lineObj, pointObj
+"""
+
+__version__ = "$Revision: 2340 $"
+# $Source$
+# $Id: mapfile.py 2340 2004-09-03 17:00:10Z jschuengel $
+
+
+# ##################################################
+#
+# import necessary modules from python and/or thuban
+#
+# ##################################################
+
+import os
+
+from Thuban.Model.color import Color, Transparent
+
+from Thuban.Model.classification import ClassGroupDefault, \
+ ClassGroupSingleton, ClassGroupRange
+
+from mapscript import layerObj, classObj, colorObj, styleObj, rectObj, symbolObj, \
+ pointObj, lineObj
+
+from Thuban.Model.layer import RasterLayer
+
+# ###################################
+#
+# Definition of dictionaries
+#
+# the dictonaries are like in mapscript and are used to make it
+# easear to unterstand the key from mapscript for the settings
+#
+# ###################################
+
+shp_type = { 0:'point',
+ 1:'line',
+ 2:'polygon',
+ 3:'raster',
+ 4:'annotation',
+ 5:'circle',
+ 6:'query'}
+
+unit_type = { 0:"inches",
+ 1:"feet",
+ 2:"miles",
+ 3:"meters",
+ 4:"kilometers",
+ 5:"dd"}
+
+legend_status_type = { 0:"OFF",
+ 1:"ON",
+ 3:"embed" }
+ # 2 = Default but is not allowed here
+
+scalebar_status_type = { 0:"OFF",
+ 1:"ON",
+ 3:"embed" }
+ # 2 = Default but is not allowed here
+
+scalebar_style_type = { 0:"0",
+ 1:"1" }
+
+scalebar_position_type = { 0:"ul",
+ 1:"lr",
+ 2:"ur",
+ 3:"ll",
+ 6:"uc",
+ 7:"lc"}
+
+layer_status_type = { 0:"OFF",
+ 1:"ON",
+ 2:"default"}
+
+legend_position_type = { 0:"ul",
+ 1:"lr",
+ 2:"ur",
+ 3:"ll",
+ 6:"uc",
+ 7:"lc"}
+
+label_size_type = { 0:"tiny",
+ 1:"small",
+ 2:"medium",
+ 3:"large",
+ 4:"giant" }
+
+#TODO: build in truetype (0:"truetype") support
+label_font_type = { 1:"bitmap" }
+
+label_position_type = { 0:"ul",
+ 1:"lr",
+ 2:"ur",
+ 3:"ll",
+ 4:"cr",
+ 5:"cl",
+ 6:"uc",
+ 7:"lc",
+ 8:"cc",
+ 10:"auto"}
+
+
+# ##################################################
+#
+# Class Definition
+#
+# ##################################################
+
+# ##################################################
+# General Classes that are not all explicitly defined through
+# a mapfile, but rather some helper-classes.
+
+class MF_Rectangle:
+ """
+ Represents an rectanle with the bottom left
+ and top right corner.
+ """
+ def __init__(self,mf_rect):
+ self._rect = mf_rect
+
+ def get_minx(self):
+ return self._rect.minx
+
+ def get_miny(self):
+ return self._rect.miny
+
+ def get_maxx(self):
+ return self._rect.maxx
+
+ def get_maxy(self):
+ return self._rect.maxy
+
+ def get_rect(self):
+ return (self._rect.minx,self._rect.miny,self._rect.maxx,self._rect.maxy)
+
+ def set_rect(self, minx, miny, maxx, maxy):
+ self._rect.minx = minx
+ self._rect.miny = miny
+ self._rect.maxx = maxx
+ self._rect.maxy = maxy
+
+class MF_Color:
+ """
+ The corresponding MapScript object contains also the
+ attribute pen which defines the stroke of the feature.
+ But this actually has nothing to do with the color and
+ therefore is not support here.
+
+ It needs to be discussed with the MapServer developers
+ whether pen would better be moved to another class.
+
+ The hex color definition which is also supported by
+ mapscript and Thuban is not supported as it does
+ not add any capability.
+
+ color is definied as RGB 0..255
+ """
+ def __init__(self, mf_color):
+ self._color = mf_color
+ self._tbc_red = (float(self.get_red())/255)
+ self._tbc_green = (float(self.get_green())/255)
+ self._tbc_blue = (float(self.get_blue())/255)
+ self._thubancolor = Color(self._tbc_red,
+ self._tbc_green,
+ self._tbc_blue)
+
+ # TODO : Check if it is necessary to use rgb colors alone
+ # or whether it is sufficient to only use the Thuban Color.
+ # In some it is necessary as red == -1 indicates that no color
+ # is set.
+ def get_red(self):
+ return self._color.red
+
+ def get_green(self):
+ return self._color.green
+
+ def get_blue(self):
+ return self._color.blue
+
+ def set_rgbcolor(self, red, green, blue):
+ self._color.red = red
+ self._color.green = green
+ self._color.blue = blue
+
+ self._tbc_red = (float(self.get_red())/255)
+ self._tbc_green = (float(self.get_green())/255)
+ self._tbc_blue = (float(self.get_blue())/255)
+ self._thubancolor = Color(self._tbc_red,
+ self._tbc_green,
+ self._tbc_blue)
+
+ def get_mfcolor(self):
+ return self._color
+
+ def get_thubancolor(self):
+ return self._thubancolor
+
+ def set_thubancolor(self, thuban_color):
+ if thuban_color != Transparent:
+ self._color.red = int(thuban_color.red * 255)
+ self._color.green = int(thuban_color.green * 255)
+ self._color.blue = int(thuban_color.blue * 255)
+ self._thubancolor = thuban_color
+
+
+class MF_Metadata:
+ """
+ Metadata is not a Object in mapscript witch can be used
+ by ease. Only the infos can get with the functions
+ "getFirstMetaDataKey", "getNextMetaDataKey" and "getMetaData".
+ To get some special Metadata you need a key. So there is a special
+ function which create a list of the metadatakeys.
+ """
+ def __init__(self, mapobj):
+ self.mapobj = mapobj
+
+ def remove_allmetadata(self):
+ keylist = self.get_metadatakeys()
+ if keylist:
+ for key in keylist:
+ self.mapobj.removeMetaData(key)
+
+ def get_metadatakeys(self):
+ keylist = []
+ try:
+ metafkey =self.mapobj.getFirstMetaDataKey()
+ keylist.append(metafkey)
+ except:
+ return None
+ else:
+ if metafkey:
+ while metafkey:
+ metafkey = self.mapobj.getNextMetaDataKey(metafkey)
+ if metafkey:
+ keylist.append(metafkey)
+ return keylist
+
+ def get_metadata(self):
+ keylist = self.get_metadatakeys()
+ metadatalist = []
+ if keylist:
+ for key in keylist:
+ metadatalist.append([key,self.mapobj.getMetaData(key)])
+ return metadatalist
+ else:
+ return None
+
+ def get_metadatabykey(self, key):
+ return self.mapobj.getMetaData(key)
+
+ def remove_metadatabykey(self, key):
+ self.mapobj.removeMetaData(key)
+
+ def add_metadata(self, key, data):
+ self.mapobj.setMetaData(key,data)
+
+# ################################################
+# Classes for MapServer Objects as they are
+# explicitly defined in a mapfile
+
+class MF_Outputformat:
+ """
+ The Outputformat defines which and how the image is
+ created by the mapserver.
+
+ The following settings are used:
+ name
+
+ The following settings are not used:
+ mimetye, driver, extension, renderer, imagemode, transparent,
+ bands, numfrotmatoptions, formatoptions, refcount, inmapfile
+ setExtension(), setMimetype(), setOption(), getOption()
+ """
+ def __init__(self, mf_outputformat):
+ self._outputformat = mf_outputformat
+
+ def get_name(self):
+ return self._outputformat.name
+
+
+class MF_Symbol:
+ """
+ defines a single symbol which is used in the Symbolset
+
+ the following settings are used:
+ name, type,
+
+ the following settings are not used:
+ sizex, sizey, points, numpoints, filled, stylelength,
+ style, imagepath, transparent, transparentcolor, character, antialias,
+ font, gap, position, linecap, linejoin, linejoinmaxsize, setPoints(),
+ getPoints(), setStyle()
+ """
+ def __init__(self, mf_symbol = "newone"):
+ # create a circle Object like shown in Thuban
+ # because Thuban don't support other symbols
+
+ # TODO: include the options to create a symbol, but
+ # first implement a methode to edit Symbols in Thuban
+ if mf_symbol == "newone":
+ mf_symbol = symbolObj("")
+ newpoint = pointObj()
+ newpoint.x = 1
+ newpoint.y = 1
+ newline = lineObj()
+ newline.add(newpoint)
+ mf_symbol.setPoints(newline)
+
+ self._symbol = mf_symbol
+
+ def get_symbolObj(self):
+ return self._symbol
+
+ def get_name(self):
+ return self._symbol.name
+
+ def set_name(self, new_name):
+ self._symbol.name = new_name
+
+ def get_type(self):
+ return self._symbol.type
+
+ def set_type(self, new_type):
+ # TODO include a function to set the type by a string
+ self._symbol.type = new_type
+
+ def get_filled(self):
+ return self._symbol.filled
+
+ def set_filled(self, new_filled):
+ if new_filled:
+ self._symbol.filled = 1
+ else:
+ self._symbol.filled = 0
+
+
+class MF_SymbolSet:
+ """
+ defines a set of symbols, may be there can only be one
+
+ the following settings are used:
+ numsymbols,
+ appendSymbol()
+
+ filename, imagecachesize, symbol, getSymbol(),
+ getSymbolByName(), index(), removeSymbol(),
+ save()
+ """
+ def __init__(self, mf_symbolset):
+ self._symbolset = mf_symbolset
+
+ # Initial Symbol List
+ self._symbols = []
+ self._i = 1
+ while self._i < self._symbolset.numsymbols:
+ self._symbols.append(MF_Symbol(self._symbolset.getSymbol(self._i)))
+ self._i += 1
+
+ def add_symbol(self, new_symbol):
+ self._symbolset.appendSymbol(new_symbol.get_symbolObj())
+ self._symbols.append(new_symbol)
+ # the save function must be run to set the symbols to the
+ # mapfile. I don't know why this ist so but it must be.
+ # the file is empty then an we can delete it
+ self._symbolset.save("tempsymbol")
+ os.remove("tempsymbol")
+
+ def get_symbol(self, symbolnr):
+ if symbolnr < self._symbolset.numsymbols:
+ return self._symbols[symbolnr-1]
+ else:
+ return None
+
+
+class MF_Class:
+ """
+ The following parameters and functions, which the mapscript style obj
+ contains, are used:
+ styles, numstyles, name, status, keyimage, layer,
+ getExpressionString(), setExpression(), getMetaData(), getFirstMetaDataKey(),
+ getNextMetaDataKey(), getStyle()
+
+ The following parameters and functions are not used:
+ label, title, template, type, minscale, maxscale, debug,
+ setExpression(), setText(), setMetaData(), drawLegendIcon(),
+ createLegendIcon(), insertStyle(), removeStyle(), moveStyleUp(),
+ moveStyleDown()
+ """
+ def __init__(self, mf_class):
+ """
+ Initialized a class from them given mapscript Class Object
+ with a list of the included styles.
+ Metadata Object will be created from the Metadata informations
+ wich are holt as a List i think.
+ """
+ self._clazz = mf_class
+ self._styles = []
+ self._numstyles = mf_class.numstyles
+ for i in range(0,self._numstyles,1):
+ self._styles.append(MF_Style(mf_class.getStyle(i)))
+
+ if self._clazz.getExpressionString() == '"(null)"':
+ self._expression = None
+ else:
+ self._expression = self._clazz.getExpressionString()
+
+ self.metadata = MF_Metadata(self._clazz)
+
+ def get_styles(self):
+ return self._styles
+
+ def get_name(self):
+ return self._clazz.name
+
+ def get_keyimage(self):
+ return self._clazz.keyimage
+
+ def get_expressionstring(self):
+ return self._expression
+
+ def set_name(self, newname):
+ self._clazz.name = newname
+
+ def set_expressionstring(self, newstring):
+ self._clazz.setExpression(newstring)
+ self._expression = self._clazz.getExpressionString()
+
+ def get_status(self):
+ if self._clazz.status == 1:
+ return True
+ else:
+ return False
+
+ def set_status(self, new_status):
+ if new_status:
+ self._clazz.status = 1
+ else:
+ self._clazz.status = 0
+
+ def add_thubanstyle(self, tb_style, type="default"):
+ """
+ added a thuban style object to the mapobject
+ """
+ new_styleobj = MF_Style(styleObj(self._clazz))
+ if type == "line":
+ new_styleobj.set_color(tb_style.GetLineColor())
+ elif type == "point":
+ # set a default symbol to show circles not only a small dot
+ # symbol "circle" must create before
+ # TODO: create a Symbol (more see MF_SymbolSet)
+ # first the default symbol circle will be created and the size 8
+ new_styleobj.set_symbolname('circle')
+ new_styleobj.set_size(8)
+ if tb_style.GetLineColor() != Transparent:
+ new_styleobj.set_linecolor(tb_style.GetLineColor())
+ new_styleobj.set_color(tb_style.GetFill())
+ else:
+ new_styleobj.set_size(tb_style.GetLineWidth())
+ if tb_style.GetLineColor() != Transparent:
+ new_styleobj.set_linecolor(tb_style.GetLineColor())
+ new_styleobj.set_color(tb_style.GetFill())
+
+
+
+class MF_Layer:
+ """
+ The following parameters and functions, which the mapscript style obj
+ contains, are used:
+
+ classitem, numclasses, name, data, type
+ getClass(), getProjection(), getExtent(), getMetaData(),
+ getFirstMetaDataKey(), getNextMetaDataKey(), status,
+
+
+ The following paramters and functions are not used:
+ index, map, header, footer, template, groupe, tolerance,
+ toleranceunits, symbolscale, minscale, maxscale, labelminscale
+ labelmaxscale, sizeunits, maxfeatures, offsite, transform, labelcache
+ postlabelcache, labelitem, labelsizeitem, labelangleitem, labelitemindex
+ labelsizeitemindex, labelangleitemindex, tileitem, tileindex, units
+ connection, connectiontype, numitems, filteritem, styleitem, requires
+ labelrequires, transparency, dump, debug, numprocessing, numjoins,
+ removeClass(), open(), close(), getShape(), getNumResults(), getResult()
+ getItem(), promote(), demote(), draw(), drawQuery(), queryByAttributes()
+ queryByPoint(), queryByRect(), queryByFeatures(), queryByShape(),
+ setFilter(), setFilterString(), setWKTProjection(), setProjection()
+ addFeature(), getNumFeatures(), setMetaData(), removeMetaData(),
+ getWMSFeatureInfoURL(), executeWFSGetFeature(), applySLD(), applySLDURL()
+ enerateSLD(), moveClassUp(), moveClassDown(), setProcessing(),
+ getProcessing(), clearProcessing()
+ """
+
+ def __init__(self, mf_layer):
+ """
+ Creates the Layer Object from the mapscript Layer Object.
+ the class objects in the layer object will be stored in
+ an array. The metadata are created as a new object.
+ """
+ self._mf_layer = mf_layer
+
+ # Create Classes
+ # there could be more then 1
+ i = -1
+ self._classes = []
+ while i < self._mf_layer.numclasses-1:
+ i += 1
+ self._classes.append(MF_Class(self._mf_layer.getClass(i)))
+
+ self._projection = MF_Projection(self._mf_layer.getProjection())
+
+ # Create Metadata
+ self._metadata = MF_Metadata(self._mf_layer)
+
+ def get_index(self):
+ return self._mf_layer.index
+
+ def get_name(self):
+ return self._mf_layer.name
+
+ def get_data(self):
+ return self._mf_layer.data
+
+ def get_classes(self):
+ return self._classes
+
+ def set_classes(self, new_classes):
+ self._classes = new_classes
+
+ def get_metadata(self):
+ return self._metadata
+
+ def set_metadata(self, new_metadata):
+ self._metadata = new_metadata
+
+ def get_type(self):
+ return shp_type[self._mf_layer.type]
+
+ def get_classitem(self):
+ return self._mf_layer.classitem
+
+ def get_projection(self):
+ return self._projection
+
+ def get_status(self):
+ # returns a integer value
+ # 0 = off, 1 = on, 2 = default(always on)
+ if self._mf_layer.status == 0:
+ return False
+ else:
+ return True
+
+ def get_group(self):
+ return self._mf_layer.group
+
+ def set_group(self, new_group):
+ self._mf_layer.group = new_group
+
+ def set_name(self, newname):
+ self._mf_layer.name = newname
+
+ def set_data(self, newdata, type="shape"):
+ if type == "raster":
+ self._mf_layer.data = newdata
+ else:
+ self._mf_layer.data = newdata[:-4]
+
+ def set_status(self, newstatus):
+ # status can set to true or false from thuban.
+ # but mapserver supports the default value
+ self._mf_layer.status = newstatus
+
+ def set_classitem(self, tb_field):
+ self._mf_layer.classitem = tb_field
+
+ def set_type(self, tb_type):
+ # if type = arc its a in shapetype line
+ if tb_type == "arc":
+ self._mf_layer.type = 1
+ if tb_type == "raster":
+ self._mf_layer.type = 3
+ if shp_type.has_key(tb_type):
+ self._mf_layer.type = tb_type
+ else:
+ for shp_paar_nr in shp_type:
+ if shp_type[shp_paar_nr] == tb_type:
+ self._mf_layer.type = shp_paar_nr
+ return
+
+ def set_projection(self, newprojection):
+ self._mfnewprojstring = ""
+ if newprojection:
+ self._newparams = newprojection.GetAllParameters()
+ for field in self._newparams:
+ self._mfnewprojstring = self._mfnewprojstring+ "," + field
+ self._mf_layer.setProjection(self._mfnewprojstring[1:])
+ self._projection.set_projection(newprojection)
+
+ def add_thubanclass(self, tb_class, type=""):
+ """
+ Add a thuban class object
+ """
+ new_class = MF_Class(classObj(self._mf_layer))
+ self._classes.append(new_class)
+ # set the class name to the Label form thuban if given,
+ # else set it to the value
+ if tb_class.GetLabel() != "":
+ new_class.set_name(tb_class.GetLabel())
+ else:
+ if isinstance(tb_class, ClassGroupDefault):
+ new_class.set_name("default")
+ elif isinstance(tb_class, ClassGroupSingleton):
+ new_class.set_name(str(tb_class.GetValue()))
+ else:
+ new_class.set_name(None)
+ if self.get_type() == "line":
+ new_class.add_thubanstyle(tb_class.GetProperties(), type="line")
+ elif self.get_type() == "point":
+ new_class.add_thubanstyle(tb_class.GetProperties(), type="point")
+ else:
+ new_class.add_thubanstyle(tb_class.GetProperties())
+ if (type == "default"):
+ return
+ # removed the following two lines to check if the expressionstring
+ # is needed for points, because if expressionstring is a range type,
+ # no expressionstring in the default group is allowed
+ elif (tb_class.Matches("DEFAULT")):
+ return
+ # new_class.set_expressionstring('/./')
+ else:
+ #check which type of expression
+ if isinstance(tb_class, ClassGroupRange):
+ # get the needed infos from the Range-String
+ self._range_begin = tb_class.GetRange()[0]
+ self._range_min = str(tb_class.GetMin())
+ self._range_max = str(tb_class.GetMax())
+ self._range_end = tb_class.GetRange()[len(tb_class.GetRange())-1]
+ self._range_umn = ""
+ self._range_classitem = self.get_classitem()
+ # generate the operator
+ if self._range_begin == "[":
+ self._range_op1 = ">="
+ elif self._range_begin == "]":
+ self._range_op1 = ">"
+ else:
+ print "error in Thuban class properties"
+ #build op1 string for the lower limit
+ self._range_op1 = "[" + self._range_classitem + "] " + \
+ self._range_op1 + " " +\
+ self._range_min
+ # build op2 string for the upper limit
+ if self._range_end == "[":
+ self._range_op2 = "<"
+ elif self._range_end == "]":
+ self._range_op2 = "<="
+ else:
+ print "error in Thuban class properties"
+
+ self._range_op2 = "[" + self._range_classitem + "] " + \
+ self._range_op2 + " " +\
+ self._range_max
+ # we only need AND here at the moment, becaus of the limits
+ # in thuban
+ self._range_combine = "AND"
+ # check if the one limit is set to inf and then
+ # remove the second expression becaus is not needed.
+ if self._range_min == "-inf":
+ self._range_combine = ""
+ self._range_op1 = ""
+ elif self._range_max == "inf":
+ self._range_combine = ""
+ self._range_op2 = ""
+ # build the expression together
+ self._range_umn = "(" + self._range_umn + \
+ self._range_op1 + " " +\
+ self._range_combine + \
+ self._range_op2 + " )"
+
+ #set the expression to the mapscript
+ new_class.set_expressionstring(self._range_umn)
+ else:
+ new_class.set_expressionstring(str(tb_class.GetValue()))
+ new_class.set_status(tb_class.IsVisible())
+
+ def remove_allclasses(self):
+ for i in range(0,len(self.get_classes()), 1):
+ self._mf_layer.removeClass(i)
+ self.set_classes([])
+
+class MF_Scalebar:
+ """
+ Represent the scalebar for a map
+
+ The following settings are used:
+ label, color, imagecolor, style, intervals, units,
+ status, position, height, width
+
+ The following settings are (not) used:
+ backgroundcolor,outlinecolor, postlabelcache
+ """
+ def __init__(self, mf_scalebar):
+ self._scalebar = mf_scalebar
+ self._color = MF_Color(self._scalebar.color)
+ self._imagecolor = MF_Color(self._scalebar.imagecolor)
+ self._label = MF_Label(self._scalebar.label)
+
+ def get_label(self):
+ return self._label
+
+ def get_color(self):
+ return self._color
+
+ def get_imagecolor(self):
+ return self._imagecolor
+
+ def get_style(self):
+ return self._scalebar.style
+
+ def set_style(self, new_style):
+ self._scalebar.style = new_style
+
+ def get_size(self):
+ #returns the size
+ return (self._scalebar.width, self._scalebar.height)
+
+ def set_size(self, new_width, new_height):
+ self._scalebar.width = new_width
+ self._scalebar.height = new_height
+
+ def get_intervals(self):
+ return self._scalebar.intervals
+
+ def set_intervals(self, new_intervals):
+ self._scalebar.intervals = new_intervals
+
+ def get_units(self):
+ #returns the unittype
+ return unit_type[self._scalebar.units]
+
+ def set_units(self, units):
+ if unit_type.has_key(units):
+ self._scalebar.units = units
+ else:
+ for unit_paar_nr in unit_type:
+ if unit_type[unit_paar_nr] == units:
+ self._scalebar.units = unit_paar_nr
+
+ def get_status(self, mode="integer"):
+ if mode == "string":
+ return scalebar_status_type[self._scalebar.status]
+ else:
+ return self._scalebar.status
+
+ def set_status(self, new_status):
+ if scalebar_status_type.has_key(new_status):
+ self._scalebar.status = new_status
+ else:
+ for scalebar_status_type_nr in scalebar_status_type:
+ if scalebar_status_type[scalebar_status_type_nr] == new_status:
+ self._scalebar.status = scalebar_status_type_nr
+
+ def get_position(self, mode="integer"):
+ if mode == "string":
+ return scalebar_position_type[self._scalebar.position]
+ else:
+ return self._scalebar.position
+
+ def set_position(self, new_position):
+ if scalebar_position_type.has_key(new_position):
+ self._scalebar.position = new_position
+ else:
+ for scalebar_position_type_nr in legend_position_type:
+ if scalebar_position_type[scalebar_position_type_nr] \
+ == new_position:
+ self._scalebar.position = scalebar_position_type_nr
+
+
+class MF_Map:
+ """
+ The following parameters and functions, which the mapscript style obj
+ contains, are used:
+
+ name, numlayers, extent, shapepath, imagecolor, imagetype, units, getLayer,
+ status, getProjection, getMetaData, getFirstMetaDataKey, getNextMetaDataKey,
+ save(), setExtent(), height, width, setProjection(), setImageType(),
+
+ The following parameters and functions are not used:
+ maxsize, layers, symbolset, fontset, labelcache,
+ transparent, interlace, imagequality, cellsize, debug, datapattern,
+ templatepattern, configoptions
+ zoomPoint(), zoomRectangle(), zoomScale(), getLayerOrder(), setLayerOrder(),
+ clone(), removeLayer(), getLayerByName(), getSymbolByName(),
+ prepareQuery(), prepareImage(), setOutputFormat(), draw(),
+ drawQuery(), drawLegend(), drawScalebar(), embedLegend(), drawLabelCache(),
+ nextLabel(), queryByPoint(), queryByRecht(), queryByFeatures(),
+ queryByShape(), setWKTProjection(), saveQuery(), saveQueryASGML(),
+ setMetaData(), removeMetaData(), setSymbolSet(), getNumSymbols(),
+ setFontSet(), saveMapContext(), loadMapContext(), moveLayerUp(),
+ moveLayerDown(), getLayersDrawingOrder(), setLayersDrawingOrder(),
+ setConfigOption(), getConfigOption(), applyConfigOptions(), applySLD(),
+ applySLDURL(), gernerateSLD(), procecssTemplate(), processLegemdTemplate(), processQueryTemplate(),
+ getOutputFormatByName(), appendOutputFormat(), removeOutputFormat(),
+ """
+ def __init__(self, mf_map):
+ """
+ Create the map object from the mapfile mapobject which is given.
+
+ All layers in the mapfile will be written to an array.
+ """
+ self._mf_map = mf_map
+ self._extent = MF_Rectangle(self._mf_map.extent)
+ self._imagecolor = MF_Color(self._mf_map.imagecolor)
+ self._web = MF_Web(self._mf_map.web)
+ self._legend = MF_Legend(self._mf_map.legend)
+ self._scalebar = MF_Scalebar(self._mf_map.scalebar)
+
+ # TODO: generate the list dynamical by alle supported formats.
+ # At the moment outputformat only get by name, but in a next
+ # version there may be a function to get the outputformat by id
+ # then there is no need to define the formattypes here
+ image_types = ['gif', 'png', 'png24', 'jpeg', 'wbmp', \
+ 'swf', 'pdf', 'imagemap']
+ self._alloutputformats = []
+ self._imagetype = self._mf_map.imagetype
+ # create a temp imagtype, because the function getOutputFormatByName()
+ # set the imagetype to the received OutputFormat
+ for fmtname in image_types:
+ theformat = self._mf_map.getOutputFormatByName(fmtname)
+ if theformat:
+ self._alloutputformats.append(MF_Outputformat(theformat))
+ self._mf_map.setImageType(self._imagetype)
+
+ self._outputformat = MF_Outputformat(self._mf_map.outputformat)
+
+ # symbols
+ self._symbolset = MF_SymbolSet(self._mf_map.symbolset)
+
+ # if the map name is not set it will return a MS string.
+ if self._mf_map.name != "MS":
+ self._name = self._mf_map.name
+ else:
+ self._name = None
+
+ self._projection = MF_Projection(self._mf_map.getProjection())
+
+ # Initial Layer List
+ self._layers = []
+ self._i = 0
+ while self._i < self._mf_map.numlayers:
+ self._layers.append(MF_Layer(self._mf_map.getLayer(self._i)))
+ self._i += 1
+
+ # Shapepath if not set, shapepath will be empty
+ if self._mf_map.shapepath:
+ self._shapepath = self._mf_map.shapepath
+ else:
+ self._shapepath = ""
+
+ # Create Metadata
+ self._metadata = MF_Metadata(self._mf_map)
+
+ def create_new_layer(self):
+ """
+ the new layer must create inside the mapobj, because mapscript
+ need the mapscript object as parameter for layerObj
+ """
+ new_layer = MF_Layer(layerObj(self._mf_map))
+ self._layers.append(new_layer)
+ # the new created layer must remove from the mapobject
+ # because all layer will create new in export.
+ #self._mf_map.removeLayer(self._mf_map.numlayers-1)
+ return new_layer
+
+ def get_mappath(self):
+ return self._mf_map.mappath
+
+ def set_mappath(self, new_mappath):
+ self._mf_map.mappath = new_mappath
+
+ def get_outputformat(self):
+ return self._outputformat
+
+ def get_alloutputformats(self):
+ return self._alloutputformats
+
+ def get_imagetype(self):
+ return self._mf_map.imagetype
+
+ def set_imagetype(self, new_imagetype):
+ self._mf_map.setImageType(new_imagetype)
+
+ def get_symbolset(self):
+ return self._symbolset
+
+ def get_status(self):
+ if self._mf_map.status == 1:
+ return True
+ else:
+ return False
+
+ def set_status(self, new_status):
+ if new_status:
+ self._mf_map.status = 1
+ else:
+ self._mf_map.status = 0
+
+ def get_scalebar(self):
+ return self._scalebar
+
+ def get_web(self):
+ return self._web
+
+ def get_legend(self):
+ return self._legend
+
+ def get_extent(self):
+ return self._extent
+
+ def get_layers(self):
+ return self._layers
+
+ def get_numlayers(self):
+ return self._mf_map.numlayers
+
+ def get_projection(self):
+ return self._projection
+
+ def get_name(self):
+ return self._name
+
+ def get_shapepath(self):
+ # where are the shape files located.
+ return self._shapepath
+
+ def set_shapepath(self, new_shapepath):
+ # where are the shape files located..
+ self._shapepath = new_shapepath
+
+ def get_imagetype(self):
+ return self._mf_map.imagetype
+
+ def get_layerorder(self):
+ # shows the order of layer as list
+ return self._mf_map.getLayerOrder()
+
+ def set_layerorder(self, new_order):
+ self._mf_map.setLayerOrder(new_order)
+
+ def get_size(self):
+ #returns the size
+ return (self._mf_map.width, self._mf_map.height)
+
+ def get_units(self):
+ #returns the unittype
+ return unit_type[self._mf_map.units]
+
+ def get_imagecolor(self):
+ return self._imagecolor
+
+ def set_name(self, newname):
+ # whitespace musst be replaced, either no
+ # mapfile will be shown in the mapserver
+ if newname:
+ newname = newname.replace(" ","_")
+ self._name = newname
+ self._mf_map.name = newname
+
+ def set_extent(self, newextent):
+ # TODO: add the shown extend here instead of the total
+ # if no size is set or if it is zero, the size will set to 1.
+ if self.get_size()[0] == - 1:
+ print "define the size first to set extent"
+ print "size is now set to (1,1)"
+ self.set_size(1,1)
+ # if an empty map is export newextent will be none
+ if newextent:
+ self._newrect = MF_Rectangle(rectObj(newextent[0],newextent[1], \
+ newextent[2],newextent[3]))
+ self._mf_map.setExtent(newextent[0],newextent[1], \
+ newextent[2],newextent[3])
+
+ def set_size(self, newwidth, newheight):
+ self._mf_map.width = newwidth
+ self._mf_map.height = newheight
+
+ def set_projection(self, projection):
+ self._mfnewprojstring = ""
+ self._newparams = projection.GetAllParameters()
+ for field in self._newparams:
+ self._mfnewprojstring = self._mfnewprojstring+ "," + field
+ self._mf_map.setProjection(self._mfnewprojstring[1:])
+ self._projection.set_projection(projection)
+
+ def set_units(self, units):
+ if unit_type.has_key(units):
+ self._mf_map.units = units
+ else:
+ for unit_paar_nr in unit_type:
+ if unit_type[unit_paar_nr] == units:
+ self._mf_map.units = unit_paar_nr
+
+ def get_metadata(self):
+ return self._metadata
+
+ def add_thubanlayer(self, tb_layer):
+ """
+ Add a thuban layer
+ """
+ # this import statement placed here, because if it is placed at the
+ # beginning of this file, it produced the following error:
+ # NameError: global name 'AnnotationLayer' is not defined
+ # don't know why this error is produced and why it works
+ # if it is placed here instead of the beginning.
+ from Extensions.umn_mapserver.mf_import import AnnotationLayer
+ if hasattr(tb_layer,"extension_umn_layerobj"):
+ #print tb_layer.extension_umn_layerobj
+ #new_layer = MF_Layer(layerObj(self._mf_map))
+ new_layer = tb_layer.extension_umn_layerobj
+ else:
+ new_layer = MF_Layer(layerObj(self._mf_map))
+ self._layers.append(new_layer)
+ tb_layer.extension_umn_layerobj = new_layer
+ new_layer.remove_allclasses()
+ # init a list to set the layerorder
+ new_layer.get_index()
+ new_layer.set_name(tb_layer.Title())
+ # TODO: implement relative pathnames
+ # yet only absolute pathnames in the LayerObj are set
+ if isinstance(tb_layer, RasterLayer ):
+ new_layer.set_data(tb_layer.GetImageFilename(), type="raster")
+ new_layer.set_type("raster")
+ new_layer.set_status(tb_layer.Visible())
+ elif isinstance(tb_layer, AnnotationLayer):
+ new_layer.set_type("annotation")
+ new_layer.set_status(tb_layer.Visible())
+ new_layer.set_data(tb_layer.ShapeStore().FileName())
+ else:
+ new_layer.set_data(tb_layer.ShapeStore().FileName())
+ new_layer.set_status(tb_layer.Visible())
+ new_layer.set_type(tb_layer.ShapeType())
+ if tb_layer.GetClassificationColumn():
+ new_layer.set_classitem(tb_layer.GetClassificationColumn())
+ if tb_layer.GetProjection():
+ new_layer.set_projection(tb_layer.GetProjection())
+ if tb_layer.GetClassification().GetNumGroups() > 0:
+ singletonexists = False
+ for group in range(0, \
+ tb_layer.GetClassification().GetNumGroups(), 1):
+ if isinstance(tb_layer.GetClassification().GetGroup(group), \
+ ClassGroupSingleton):
+ singletonexists = True
+ new_layer.add_thubanclass( \
+ tb_layer.GetClassification().GetGroup(group))
+ new_layer.add_thubanclass( \
+ tb_layer.GetClassification().GetDefaultGroup())
+ # remove the classitem if one singleton exists
+ if singletonexists == False:
+ new_layer.set_classitem(None)
+ else:
+ new_layer.add_thubanclass( \
+ tb_layer.GetClassification().GetDefaultGroup(), \
+ type="default")
+ # set the projection to the layer.
+ # if the layer has its own definition use it,
+ # else use the main projection
+ if tb_layer.GetProjection():
+ new_layer.set_projection(tb_layer.GetProjection())
+ else:
+ new_layer.set_projection(self._projection.get_projection())
+
+ def remove_layer(self, delnr):
+ if delnr < len(self._layers):
+ # if a layer is removed, the links for the mapscript layer and
+ # the metadata must set new
+ # TODO: All other object in a layer obj must set a new, e.g proj.
+ for ll in range(len(self._layers)-1, delnr, -1):
+ self._layers[ll]._mf_layer = self._layers[ll-1]._mf_layer
+ self._layers[ll].set_metadata(self._layers[ll-1].get_metadata())
+
+ self._mf_map.removeLayer(delnr)
+ self._layers.pop(delnr)
+
+ def save_map(self, filepath):
+ # save the Map
+ # maybe an own saver can implement here
+ self._mf_map.save(filepath)
+
+
+class MF_Web:
+ """
+ Save the Web settings
+
+ The following parametes are used:
+ imagepath, imageurl, queryformat,
+
+ The following parameters are not used:
+ log, map, template, header, footer, empty, error, extent,
+ minscale, maxscale, mintemplate, maxtemplate
+ """
+ def __init__(self, mf_web):
+ self._mf_web = mf_web
+
+ def get_imagepath(self):
+ return self._mf_web.imagepath
+
+ def set_imagepath(self, new_imagepath):
+ self._mf_web.imagepath = new_imagepath
+
+ def get_imageurl(self):
+ return self._mf_web.imageurl
+
+ def get_template(self):
+ return self._mf_web.template
+
+ def set_template(self, new_template):
+ self._mf_web.template = new_template
+
+ def set_imageurl(self, new_imageurl):
+ self._mf_web.imageurl = new_imageurl
+
+ def get_queryformat(self):
+ return self._mf_web.queryformat
+
+ def set_queryformat(self, new_queryformat):
+ self._mf_web.imagepath = new_queryformat
+
+
+class MF_Label:
+ """
+ The following parameters from mapscript are used:
+ type, color, size, offsetx, offsety, partials, force, buffer,
+ minfeaturesize, mindistance,
+
+ The following parameters are not used:
+ font, outlinecolor, shadowcolor, shadowsizex, shadowsizey,
+ backgroundcolor, backgroundshadowcolor, backgroundshadowsizex,
+ backgroundshadowsizey, sizescaled, minsize, maxsize, position, angle,
+ autoangle, antialias, wrap, autominfeaturesize,
+ """
+ def __init__(self, mf_label):
+ """
+ Create a legend obj from the existing mapfile
+ """
+ self._label = mf_label
+ self._color = MF_Color(self._label.color)
+
+ def get_size(self):
+ return self._label.size
+
+ def set_size(self, new_size):
+ if label_size_type.has_key(new_size):
+ self._label.size = new_size
+ for label_size_type_nr in label_size_type:
+ if label_size_type[label_size_type_nr] == new_size:
+ self._label.size = label_size_type_nr
+ else:
+ self._label.size = new_size
+
+ def get_color(self):
+ return self._color
+
+ def get_partials(self):
+ if self._label.partials == 1:
+ return True
+ else:
+ return False
+
+ def set_partials(self, new_partials):
+ # if partials = True
+ if new_partials:
+ self._label.partials = 1
+ elif new_partials == False:
+ self._label.partials = 0
+ else:
+ print "must be boolean"
+
+ def get_buffer(self):
+ return self._label.buffer
+
+ def set_buffer(self, new_buffer):
+ self._label.buffer = new_buffer
+
+ def get_mindistance(self):
+ return self._label.mindistance
+
+ def set_mindistance(self, new_mindistance):
+ self._label.mindistance = new_mindistance
+
+ def get_minfeaturesize(self):
+ return self._label.minfeaturesize
+
+ def set_minfeaturesize(self, new_minfeaturesize):
+ self._label.minfeaturesize = new_minfeaturesize
+
+ def get_position(self, mode="integer"):
+ if mode == "string":
+ return label_position_type[self._label.position]
+ else:
+ return self._label.position
+
+ def set_position(self, new_position):
+ if label_position_type.has_key(new_position):
+ self._label.position = new_position
+ else:
+ for label_position_type_nr in label_position_type:
+ if label_position_type[label_position_type_nr] == new_position:
+ self._label.position = label_position_type_nr
+
+ def get_force(self):
+ if self._label.force == 1:
+ return True
+ else:
+ return False
+
+ def set_force(self, new_force):
+ if new_force:
+ self._label.force = 1
+ else:
+ self._label.force = 0
+
+ def get_type(self):
+ return label_font_type[self._label.type]
+
+ def set_type(self, new_type):
+ if label_font_type.has_key(new_type):
+ self._label.type = new_type
+ else:
+ for label_font_type_nr in label_font_type:
+ if label_font_type[label_font_type_nr] == new_type:
+ self._label.type = label_font_type_nr
+
+ def get_offset(self):
+ return (self._label.offsetx, self._label.offsety)
+
+ def set_offset(self, new_offsetx, new_offsety):
+ self._label.offsetx = new_offsetx
+ self._label.offsety = new_offsety
+
+
+class MF_Legend:
+ """
+ The following parameters are (not) used:
+ imagecolor, label, keysizex, keysizey, status, position,
+
+ The following parameters are not used:
+ keyspacingx, keyspacingy,
+ outlinecolor, height, width, postlabelcache, template, map
+ """
+ def __init__(self, mf_legend):
+ """
+ Create a legend obj from the existing mapfile
+ """
+ self._mf_legend = mf_legend
+ self._imagecolor = MF_Color(self._mf_legend.imagecolor)
+ self._label = MF_Label(self._mf_legend.label)
+
+ def get_imagecolor(self):
+ return self._imagecolor
+
+ def get_label(self):
+ return self._label
+
+ def get_keysize(self):
+ return (self._mf_legend.keysizex, self._mf_legend.keysizey)
+
+ def set_keysize(self, new_keysizex, new_keysizey):
+ self._mf_legend.keysizex = new_keysizex
+ self._mf_legend.keysizey = new_keysizey
+
+ def get_keyspacing(self):
+ return (self._mf_legend.keyspacingx, self._mf_legend.keyspacingy)
+
+ def set_keyspacing(self, new_keyspacingx, new_keyspacingy):
+ self._mf_legend.keyspacingx = new_keyspacingx
+ self._mf_legend.keyspacingy = new_keyspacingy
+
+ def get_status(self, mode="integer"):
+ if mode == "string":
+ return legend_status_type[self._mf_legend.status]
+ else:
+ return self._mf_legend.status
+
+ def set_status(self, new_status):
+ if legend_status_type.has_key(new_status):
+ self._mf_legend.status = new_status
+ else:
+ for legend_status_type_nr in legend_status_type:
+ if legend_status_type[legend_status_type_nr] == new_status:
+ self._mf_legend.status = legend_status_type_nr
+
+ def get_position(self, mode="integer"):
+ if mode == "string":
+ return legend_position_type[self._mf_legend.position]
+ else:
+ return self._mf_legend.position
+
+ def set_position(self, new_position):
+ if legend_position_type.has_key(new_position):
+ self._mf_legend.position = new_position
+ else:
+ for legend_position_type_nr in legend_position_type:
+ if legend_position_type[legend_position_type_nr]== new_position:
+ self._mf_legend.position = legend_position_type_nr
+
+class MF_Projection:
+ """
+ The following parameter, which the mapscript style obj contains is used:
+
+ numargs
+ """
+
+ def __init__(self, mf_projection):
+ """
+ Create a projection object from the given mapscript projection
+ object. If it is a epsg code the extracted from the string
+ (e.g."init=epsg:xxxx"), else the projection parameters will
+ be splitted and an array with the parameters will be creaded.
+ """
+ self._mfprojstring = mf_projection
+ self._projstring = self._mfprojstring
+ self._epsgcode = None
+ self._params = None
+ if self._mfprojstring:
+ if self._mfprojstring.find("init=epsg:") != -1:
+ self._initcode, self._epsgcode = self._mfprojstring.split(':')
+ else:
+ self._params = []
+ self._params = self._mfprojstring.split("+")
+ if self._params[0] == "":
+ self._params.remove("")
+
+ def epsg_code_to_projection(self, epsg):
+ """
+ Find the projection for the given epsg code.
+
+ Copied from Extension/wms/layer.py
+
+ epsg -- EPSG code as string
+ """
+ #Needed only for this function
+ from Thuban.Model.resource import get_system_proj_file, EPSG_PROJ_FILE,\
+ EPSG_DEPRECATED_PROJ_FILE
+
+ proj_file, warnings = get_system_proj_file(EPSG_PROJ_FILE)
+
+ for proj in proj_file.GetProjections():
+ if proj.EPSGCode() == epsg:
+ return proj
+
+ proj_file, warnings = get_system_proj_file(EPSG_DEPRECATED_PROJ_FILE)
+ for proj in proj_file.GetProjections():
+ if proj.EPSGCode() == epsg:
+ return proj
+ return None
+
+ def get_params(self):
+ #Parameter from the mf_projectionstring as Array
+ return self._params
+
+ def get_epsgcode(self):
+ # returnes the epsg number
+ return self._epsgcode
+
+ def get_epsgproj(self):
+ # get an epsg projectionobject
+ return self.epsg_code_to_projection(self._epsgcode)
+
+ def get_projection(self):
+ return self._projstring
+
+ def set_projection(self, newprojection):
+ self._projstring = newprojection
+ self._params = newprojection.GetAllParameters()
+ self._mfnewprojstring = ""
+ for field in self._params:
+ self._mfnewprojstring = self._mfnewprojstring+ "+" + field
+ self._mfprojstring = self._mfnewprojstring
+
+
+class MF_Style:
+ """
+ The following parameters, which the mapscript style obj
+ contains, are used:
+ color, backgroundcolor, outlinecolor, size, symbolname
+
+ The following are not used:
+ symbol, sizescaled, minsize, maxsize, offsetx, offsety,
+ antialias
+ """
+
+ def __init__(self, mf_style):
+ """
+ Create a style object from the given mapscript style object.
+ The color Object from the color and the outlinecolor parameter
+ will be created. if the color (red, green or blue) is -1 there
+ is no definition in the mapfile and so there is no color object,
+ it will set to 'None'.
+ """
+ self._style = mf_style
+ if self._style.color.red == -1:
+ self._color = None
+ else:
+ self._color = MF_Color(self._style.color)
+ if self._style.outlinecolor.red == -1:
+ self._outlinecolor = None
+ else:
+ self._outlinecolor = MF_Color(self._style.outlinecolor)
+
+ def get_color(self):
+ return self._color
+
+ def get_outlinecolor(self):
+ return self._outlinecolor
+
+ def get_size(self):
+ return self._style.size
+
+ def set_linecolor(self, tb_color):
+ self._color = tb_color
+ new_linecolor = MF_Color(colorObj())
+ new_linecolor.set_thubancolor(tb_color)
+ self._outlinecolor = new_linecolor
+ self._style.outlinecolor = new_linecolor.get_mfcolor()
+
+ def set_color(self, tb_color):
+ self._color = tb_color
+ new_color = MF_Color(colorObj())
+ new_color.set_thubancolor(tb_color)
+ self._color = new_color
+ self._style.color = new_color.get_mfcolor()
+
+ def set_size(self, newsize):
+ self._style.size = newsize
+
+ def set_symbolname(self, newsymbol):
+ # its possible to use stringnames instead of numbers
+ self._style.symbolname = newsymbol
+
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_export.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_export.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_export.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,200 @@
+# Copyright (C) 2004 by Intevation GmbH
+# -*- coding:latin1 -*-
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+This modul extend Thuban with the possibility to handle
+UMN MapServer mapfiles.
+"""
+
+__version__ = "$Revision: 2719 $"
+# $Source$
+# $Id: mf_export.py 2719 2007-01-08 16:30:29Z dpinte $
+
+
+# ###################################
+#
+# import necessary modules
+#
+# ###################################
+
+import os
+
+# mapscript
+from mapscript import mapObj
+
+# wx.Python support
+import wx
+
+# Thuban
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# needed to add the new menu
+from Thuban.UI.mainwindow import main_menu
+
+# import Map Object for the Mapfile
+from mapfile import MF_Map, MF_Symbol
+
+# ###################################
+#
+# Mainpart of the Extension
+#
+# ###################################
+
+def tbproj_to_map(tb_map, map):
+ """
+ set the projection from thuban to the mapscript
+ """
+ # TODO: epsg code support
+ # epsg will convert to parameters at the moment
+ tb_proj = tb_map.GetProjection()
+ if tb_proj:
+ map.set_projection(tb_proj)
+
+def tblayer_to_map(tb_map, map):
+ """
+ added all layers which are displayed in thuban to the mapscript
+ if the are new, else use the associated mapobjects.
+ All other layers will be removed
+ """
+ tb_layers = tb_map.Layers()
+ oldindex = map.get_layerorder()
+ indexlist = []
+ for layer in tb_layers:
+ map.add_thubanlayer(layer)
+ layind = layer.extension_umn_layerobj.get_index()
+ indexlist.append(layind)
+ bigint = 0
+ for rmnr in oldindex:
+ if rmnr > bigint:
+ bigint = rmnr
+ removelist = []
+ for rnr in range(0, bigint+1, 1):
+ if rnr not in indexlist:
+ removelist.append(rnr)
+
+ for i in range(len(removelist), 0, -1):
+ map.remove_layer(removelist[i-1])
+
+ map.set_layerorder(tuple(indexlist))
+
+def thuban_to_map(tb_context, map):
+ """
+ add all context from thuban to the mapscript
+ """
+ # get the thuban map
+ tb_map = tb_context.mainwindow.canvas.Map()
+ # set the title
+ map.set_name(tb_map.Title())
+ # set the projection
+ tbproj_to_map(tb_map, map)
+ # set the extent
+ tb_bbox = tb_context.mainwindow.canvas.VisibleExtent()
+ # Size must be set before, because mapscript checks it
+ # when extent is set
+ map.set_extent(tb_bbox)
+ tblayer_to_map(tb_map, map)
+
+def add_circle_symbol(map):
+ """
+ Added a circle object like the one shown in thuban
+ """
+ if map.get_symbolset().get_symbol(1):
+ return
+ else:
+ new_symbol = MF_Symbol()
+ new_symbol.set_name("circle")
+ new_symbol.set_type(2)
+ new_symbol.set_filled(True)
+ map.get_symbolset().add_symbol(new_symbol)
+
+def write_creatorcomment(path,file):
+ """
+ Added a short comment to the created map file to show
+ that the file is generated automatic
+ """
+ thuban_umn_comment = "# \n" + \
+ "# Map file generated by Thuban (umn_mapserver Extension) \n" + \
+ "# \n \n"
+ datafile = os.path.join(path,file)
+
+ in_file = open(datafile,"r")
+ text_in_file = in_file.read()
+ in_file.close()
+
+ out_file = open(datafile,"w")
+ out_file.write(thuban_umn_comment)
+ out_file.write(text_in_file) # text in Datei schreiben
+ out_file.close() # Datei schliessen
+
+def export_mapfile(context):
+ """
+ Exports an existing mapobj and set all stuff from thuban to
+ the mapobj
+ """
+ theMap = context.mainwindow.canvas.Map().extension_umn_mapobj
+
+ dlg = wx.FileDialog(context.mainwindow, "Save file as...", ".", "",
+ "UMN MapServer Mapfiles (*.map)|*.map|" \
+ "All files (*.*)|*.*",
+ wx.SAVE |wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetDirectory()
+ file = dlg.GetFilename()
+ dlg.Destroy()
+ else:
+ return
+
+ # set all thuban context to the mapobj
+ thuban_to_map(context, theMap)
+
+ #add symbol
+ add_circle_symbol(theMap)
+
+ # shapepath vom mapfile
+ theMap.set_shapepath("")
+
+ # save the map with the integrated mapscript saver
+ theMap.save_map(os.path.join(path,file))
+
+ # this funktion will write a commend to the generated mapfile
+ # that shows that the file is generated by thuban
+ write_creatorcomment(path,file)
+
+
+# check if an mapobj exists, to control the menuitem is available or not
+def _has_umn_mapobj(context):
+ """Return true if a umn_mapobj exists"""
+ return hasattr(context.mainwindow.canvas.Map(), "extension_umn_mapobj")
+
+# ###################################
+#
+# Hook in MapServer Extension into Thuban
+#
+# ###################################
+
+# register the new command
+registry.Add(Command("export_new_mapfile", _("Export mapfile"), \
+ export_mapfile, helptext = _("Create a new mapfile"), \
+ sensitive = _has_umn_mapobj))
+
+# find the extensions menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu("experimental", \
+ _("Experimenta&l"))
+# find the extension menu and add a new submenu if found
+mapserver_menu = experimental_menu.FindOrInsertMenu("mapserver", \
+ _("&MapServer"))
+
+# finally add the new entry to the extensions menu
+mapserver_menu.InsertItem("export_new_mapfile", after="edit_mapfile")
+
+
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_handle.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_handle.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_handle.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1408 @@
+# -*- coding:latin1 -*-
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+This modul extend Thuban with the possibility to handle
+UMN MapServer mapfiles.
+"""
+
+__version__ = "$Revision: 2719 $"
+# $Source$
+# $Id: mf_handle.py 2719 2007-01-08 16:30:29Z dpinte $
+
+
+# ###################################
+#
+# import necessary modules
+#
+# ###################################
+
+import os, sys
+
+# mapscript
+from mapscript import mapObj, layerObj
+
+# wx.Python support
+import wx
+from wx import grid
+
+# Thuban
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# needed to add the new menu
+from Thuban.UI.mainwindow import main_menu
+
+# import Map Object for the Mapfile
+from mapfile import MF_Map
+
+from Thuban.UI.colordialog import ColorDialog
+
+from mapfile import unit_type, legend_status_type, legend_position_type, \
+ label_font_type, scalebar_status_type, scalebar_style_type, \
+ scalebar_position_type, label_position_type
+
+# ###################################
+#
+# Mainpart of the Extension
+#
+# ###################################
+
+ID_COLOR_CHANGE= 8001
+ID_IMGCOLOR_CHANGE = 8002
+
+class Map_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # parent.canvas.Map()
+ self.tb_map = parent.canvas.Map()
+ self.tb_map_umn = self.tb_map.extension_umn_mapobj
+
+ # create name
+ box_name = wx.BoxSizer(wx.HORIZONTAL)
+ box_name.Add(wx.StaticText(self, -1, _("Map-Name:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ box_name.Add(wx.StaticText(self, -1, self.tb_map.Title()), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ #create size settings
+ insidetxt = self.tb_map_umn.get_size()
+ staticSize = wx.StaticBox(self, 1010, _("Size"), style = 0,
+ name = "staticBox", )
+ box_size = wx.StaticBoxSizer(staticSize, wx.VERTICAL)
+
+ box_sizepartWidth = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartWidth.Add(wx.StaticText(self, -1, _("Width: ")), 0, wx.ALL, 4)
+ self.text_width = wx.TextCtrl(self, -1, str(insidetxt[0]))
+ box_sizepartWidth.Add(self.text_width, 2, wx.ALL, 4)
+ box_size.Add(box_sizepartWidth, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
+ box_sizepartHeight = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartHeight.Add(wx.StaticText(self, -1, _("Height: ")), 0,
+ wx.ALL, 4)
+ self.text_height = wx.TextCtrl(self, -1, str(insidetxt[1]))
+ box_sizepartHeight.Add(self.text_height, 2, wx.ALL, 4)
+ box_size.Add(box_sizepartHeight, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
+
+ # get the web object
+ self.tb_map = parent.canvas.Map()
+ self.tb_map_umn = self.tb_map.extension_umn_mapobj
+
+ #get the imagetype
+ umn_imagetype = self.tb_map_umn.get_imagetype()
+ # create a list with the outputformat names
+ umn_outputformats = []
+ for format in self.tb_map_umn.get_alloutputformats():
+ umn_outputformats.append(format.get_name())
+ #Imagetype selector
+ box_imagetypeStatic = wx.StaticBox(self, -1, _("Image Type"),
+ style = 0, name = "imagetype")
+ box_imagetype = wx.StaticBoxSizer(box_imagetypeStatic, wx.VERTICAL)
+ self.choice_imgtype = wx.Choice(self, 8060, (80, 50),
+ choices = umn_outputformats)
+ EVT_CHOICE(self, 8060, self.EvtChoiceBox)
+ self.choice_imgtype.SetStringSelection(umn_imagetype)
+ box_imagetype.Add(self.choice_imgtype,0, wx.EXPAND, wx.ALL, 5)
+
+ #unittype
+ insideunit = self.tb_map_umn.get_units()
+ #Unittype selector
+ box_unitsStatic = wx.StaticBox(self, 1011, _("Unit Type"),
+ style = 0, name = "imagecolor")
+ box_units = wx.StaticBoxSizer(box_unitsStatic, wx.VERTICAL)
+ sam = []
+ for key in unit_type:
+ sam.append(unit_type[key])
+ self.choice_units = wx.Choice(self, 40, (80, 50), choices = sam)
+ self.choice_units.SetStringSelection(insideunit)
+ box_units.Add(self.choice_units,0, wx.EXPAND, wx.ALL, 5)
+
+ # color chouser
+ box_colorStatic = wx.StaticBox(self, 1011, _("ImageColor"),
+ style = 0, name = "imagecolor")
+ box_color = wx.StaticBoxSizer(box_colorStatic, wx.VERTICAL)
+
+ # preview box
+ self.previewcolor = wx.Panel(self,99, name = 'backgroundPanel',
+ style = wx.SIMPLE_BORDER | wx.CLIP_CHILDREN)
+ imagecolor = self.tb_map_umn.get_imagecolor()
+ self.previewcolor.SetBackgroundColour(wx.Colour(imagecolor.get_red(),
+ imagecolor.get_green(), imagecolor.get_blue()))
+ box_color.Add(self.previewcolor, 1, wx.GROW | wx.ALL, 5)
+ # color change button, opens a new color dialog
+ button = wx.Button(self, ID_COLOR_CHANGE, _("Change Color"))
+ button.SetFocus()
+ EVT_BUTTON(self, ID_COLOR_CHANGE, self.OnChangeColor)
+ box_color.Add(button, 1, wx.EXPAND|wx.ALL, 5)
+
+ # status
+ umn_status = self.tb_map_umn.get_status()
+ self.choice_status = wx.RadioBox(self, -1, choices=["True","False"],
+ label='status', majorDimension=1,
+ name='status check', size=wx.DefaultSize, style=wx.RA_SPECIFY_ROWS)
+ self.choice_status.SetStringSelection(str(umn_status))
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #button functions
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ #add all boxes to the box top
+ top = wx.BoxSizer(wx.VERTICAL)
+ top.Add(box_name, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_size, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_imagetype,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_units,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_color,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(self.choice_status,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def OnChangeColor(self, event):
+ cur = self.tb_map_umn.get_imagecolor().get_thubancolor()
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+ self.retcolor = None
+ if dialog.ShowModal() == wx.ID_OK:
+ self.retcolor = dialog.GetColor()
+ dialog.Destroy()
+ if self.retcolor:
+ self.redcolor = int(round(self.retcolor.red*255))
+ self.greencolor = int(round(self.retcolor.green*255))
+ self.bluecolor = int(round(self.retcolor.blue*255))
+ self.previewcolor.SetBackgroundColour(wx.Colour((self.redcolor),
+ int(self.greencolor), int(self.bluecolor)))
+ # refresh the colorbox to show the new color
+ self.previewcolor.Refresh()
+
+ def EvtChoiceBox(self, event):
+ outformat = self.tb_map_umn.get_outputformat().get_name()
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.tb_map_umn.set_size(int(self.text_width.GetValue()),
+ int(self.text_height.GetValue()))
+ self.tb_map_umn.set_units(self.choice_units.GetStringSelection())
+ if self.choice_status.GetStringSelection() == "True":
+ self.tb_map_umn.set_status(True)
+ else:
+ self.tb_map_umn.set_status(False)
+ previewcolor = self.previewcolor.GetBackgroundColour()
+ self.tb_map_umn.get_imagecolor().set_rgbcolor(previewcolor.Red(),
+ previewcolor.Green(), previewcolor.Blue())
+ self.tb_map_umn.set_imagetype(self.choice_imgtype.GetStringSelection())
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+
+class Web_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ self.tb_map = parent.canvas.Map()
+ self.umn_web = self.tb_map.extension_umn_mapobj.get_web()
+
+ # Template
+ box_template = wx.BoxSizer(wx.HORIZONTAL)
+ box_template.Add(wx.StaticText(self, -1, _("Template:")), 0,
+ wx.ALL|wx.ALIGN_LEFT, 4)
+ self.text_template = wx.TextCtrl(self, -1,
+ str(self.umn_web.get_template()))
+ self.text_template.SetSize((250,self.text_template.GetSize()[1]))
+ box_template.Add(self.text_template, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ # Imagepath
+ box_imagepath = wx.BoxSizer(wx.HORIZONTAL)
+ box_imagepath.Add(wx.StaticText(self, -1, _("Imagepath:")), 0,
+ wx.ALL|wx.ALIGN_LEFT, 4)
+ self.text_imagepath = wx.TextCtrl(self, -1,
+ str(self.umn_web.get_imagepath()))
+ box_imagepath.Add(self.text_imagepath, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ # Imageurl
+ box_imageurl = wx.BoxSizer(wx.HORIZONTAL)
+ box_imageurl.Add(wx.StaticText(self, -1, _("Imageurl:")), 0,
+ wx.ALL|wx.ALIGN_LEFT, 4)
+ self.text_imageurl = wx.TextCtrl(self, -1,
+ str(self.umn_web.get_imageurl()))
+ box_imageurl.Add(self.text_imageurl, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the final dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+ top.Add(box_template, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_imagepath, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_imageurl, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.umn_web.set_template(self.text_template.GetValue())
+ self.umn_web.set_imagepath(self.text_imagepath.GetValue())
+ self.umn_web.set_imageurl(self.text_imageurl.GetValue())
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+ID_METADATA_CHANGE = 8020
+
+from Extensions.umn_mapserver.mapfile import MF_Layer
+
+class Layer_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ self.tb_layer = parent.current_layer()
+ if hasattr(self.tb_layer,"extension_umn_layerobj"):
+ self.umn_layer = self.tb_layer.extension_umn_layerobj
+ else:
+ newlayerobj = parent.canvas.Map().extension_umn_mapobj.create_new_layer()
+ self.tb_layer.extension_umn_layerobj = newlayerobj
+ self.umn_layer = self.tb_layer.extension_umn_layerobj
+
+ # create name
+ layer_name = wx.BoxSizer(wx.HORIZONTAL)
+ layer_name.Add(wx.StaticText(self, -1, _("Layer-Name:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ layer_name.Add(wx.StaticText(self, -1, self.tb_layer.Title()), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ # metadata button
+ metadata_button = wx.Button(self, ID_METADATA_CHANGE, _("Edit Metadata"))
+ EVT_BUTTON(self, ID_METADATA_CHANGE, self.OnChangeMetadata)
+
+ # Group
+ box_group = wx.BoxSizer(wx.HORIZONTAL)
+ if self.umn_layer.get_group():
+ umn_layer_group = self.umn_layer.get_group()
+ else:
+ umn_layer_group = ""
+ box_group.Add(wx.StaticText(self, -1, _("Group:")), 0,
+ wx.ALL|wx.ALIGN_LEFT, 4)
+ self.text_group = wx.TextCtrl(self, -1,
+ str(umn_layer_group))
+ self.text_group.SetSize((250,self.text_group.GetSize()[1]))
+ box_group.Add(self.text_group, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ # buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the final dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+ #top.Add(box_template, 0, wx.EXPAND |wx.ALL, 5)
+ top.Add(layer_name, 0, wx.EXPAND|wx.ALL, 5)
+ top.Add(box_group, 0, wx.EXPAND|wx.ALL, 5)
+ top.Add(metadata_button, 0, wx.EXPAND|wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def OnChangeMetadata(self, event):
+ # set the umn_label for scalebar so the Label_Dialog can be used
+ self.umn_metadata= self.umn_layer.get_metadata()
+ dialog = Metadata_Dialog(self, -1, "Layer Metadata Settings",
+ size=wx.Size(450, 200),
+ style = wx.DEFAULT_DIALOG_STYLE
+ )
+ dialog.CenterOnScreen()
+ if dialog.ShowModal() == wx.ID_OK:
+ return
+ dialog.Destroy()
+
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ if self.text_group.GetValue() == "":
+ self.umn_layer.set_group(None)
+ else:
+ self.umn_layer.set_group(self.text_group.GetValue())
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+
+ID_LABEL_CHANGE = 8011
+
+class Legend_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ self.tb_map = parent.canvas.Map()
+ self.umn_legend = self.tb_map.extension_umn_mapobj.get_legend()
+
+ # create the Keysize
+ keySize = wx.StaticBox(self, 1010, _("KeySize"), style = 0,
+ name = "KeySize Box", )
+ box_keysize = wx.StaticBoxSizer(keySize, wx.VERTICAL)
+ umn_legend_keysize = self.umn_legend.get_keysize()
+ box_sizepartWidth = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartWidth.Add(wx.StaticText(self, -1, _("Width: ")), 0, wx.ALL, 2)
+ self.text_keysize_width = wx.SpinCtrl(self, -1,
+ value=str(umn_legend_keysize[0]), max=100, min=0,
+ name='keywidth', style=wx.SP_ARROW_KEYS)
+ box_sizepartWidth.Add(self.text_keysize_width, 2, wx.ALL, 2)
+ box_keysize.Add(box_sizepartWidth, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+ box_sizepartHeight = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartHeight.Add(wx.StaticText(self, -1, _("Height: ")), 0, wx.ALL, 2),
+ self.text_keysize_height = wx.SpinCtrl(self, -1,
+ value=str(umn_legend_keysize[1]), max=100, min=0,
+ name='keyheight', style=wx.SP_ARROW_KEYS)
+ box_sizepartHeight.Add(self.text_keysize_height, 2, wx.ALL, 2)
+ box_keysize.Add(box_sizepartHeight, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # create the Keyspacing
+ keySpacing= wx.StaticBox(self, 1010, _("KeySpacing"), style = 0,
+ name = "KeySpacing Box", )
+ box_keyspacing = wx.StaticBoxSizer(keySpacing, wx.VERTICAL)
+ umn_legend_keyspacing = self.umn_legend.get_keyspacing()
+ box_sizepartWidth = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartWidth.Add(wx.StaticText(self, -1, _("Width: ")), 0, wx.ALL, 2)
+ self.text_keyspacing_width = wx.SpinCtrl(self, -1,
+ value=str(umn_legend_keyspacing[0]), max=100,
+ min=0, name='spacingwidth', style=wx.SP_ARROW_KEYS)
+ box_sizepartWidth.Add(self.text_keyspacing_width, 2, wx.ALL, 2)
+ box_keyspacing.Add(box_sizepartWidth, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+ box_sizepartHeight = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartHeight.Add(wx.StaticText(self, -1, _("Height: ")), 0, wx.ALL, 2),
+ self.text_keyspacing_height = wx.SpinCtrl(self, -1,
+ value=str(umn_legend_keyspacing[1]), max=100,
+ min=0,name='spacingheight', style=wx.SP_ARROW_KEYS)
+ box_sizepartHeight.Add(self.text_keyspacing_height, 2, wx.ALL, 2)
+ box_keyspacing.Add(box_sizepartHeight, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # color chooser
+ box_colorStatic = wx.StaticBox(self, 1011, _("ImageColor"), style = 0,
+ name = "imagecolor")
+ box_color = wx.StaticBoxSizer(box_colorStatic, wx.VERTICAL)
+ # preview box
+ self.previewcolor = wx.Panel(self, 99, name = 'imagecolorPanel',
+ style = wx.SIMPLE_BORDER | wx.CLIP_CHILDREN)
+ imagecolor = self.umn_legend.get_imagecolor()
+ self.previewcolor.SetBackgroundColour(wx.Colour(imagecolor.get_red(),
+ imagecolor.get_green(), imagecolor.get_blue()))
+ box_color.Add(self.previewcolor, 1, wx.GROW | wx.ALL, 5)
+ # color change button, opens a new color dialog
+ button = wx.Button(self, ID_COLOR_CHANGE, _("Change Color"))
+ button.SetFocus()
+ EVT_BUTTON(self, ID_COLOR_CHANGE, self.OnChangeColor)
+ box_color.Add(button, 1, wx.EXPAND|wx.ALL, 5)
+
+ # status
+ umn_legend_status= self.umn_legend.get_status(mode="string")
+ possible_choices = []
+ for key in legend_status_type:
+ possible_choices.append(legend_status_type[key])
+ self.choice_status = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Status', majorDimension=1,
+ name='status check', size=wx.DefaultSize, style=wx.RA_SPECIFY_ROWS)
+ self.choice_status.SetStringSelection(umn_legend_status)
+
+ # create the positionbox
+ umn_legend_position= self.umn_legend.get_position(mode="string")
+ possible_choices = []
+ for key in legend_position_type:
+ possible_choices.append(legend_position_type[key])
+ self.choice_position = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Position', majorDimension=1,
+ name='position check',
+ size=wx.DefaultSize,
+ style=wx.RA_SPECIFY_ROWS)
+ self.choice_position.SetStringSelection(umn_legend_position)
+
+ # button for label
+ labelbutton = wx.Button(self, ID_LABEL_CHANGE, _("Change Label"))
+ EVT_BUTTON(self, ID_LABEL_CHANGE, self.OnChangeLabel)
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the final layout
+ top = wx.BoxSizer(wx.VERTICAL)
+ top.Add(box_keysize,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_keyspacing,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_color,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(self.choice_status,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(self.choice_position,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(labelbutton, 1, wx.EXPAND|wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def OnChangeLabel(self, event):
+ self.umn_label = self.umn_legend.get_label()
+ dialog = Label_Dialog(self, -1, "Legend Label Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE
+ )
+ dialog.CenterOnScreen()
+ if dialog.ShowModal() == wx.ID_OK:
+ return
+ dialog.Destroy()
+
+ def OnChangeColor(self, event):
+ cur = self.umn_legend.get_imagecolor().get_thubancolor()
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+ self.retcolor = None
+ if dialog.ShowModal() == wx.ID_OK:
+ self.retcolor = dialog.GetColor()
+ dialog.Destroy()
+ if self.retcolor:
+ self.redcolor = int(round(self.retcolor.red*255))
+ self.greencolor = int(round(self.retcolor.green*255))
+ self.bluecolor = int(round(self.retcolor.blue*255))
+ self.previewcolor.SetBackgroundColour(wx.Colour(int(self.redcolor),
+ int(self.greencolor),
+ int(self.bluecolor)))
+ # refresh the colorbox to show the new color
+ self.previewcolor.Refresh()
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.umn_legend.set_keysize(self.text_keysize_width.GetValue(),
+ self.text_keysize_height.GetValue())
+ self.umn_legend.set_keyspacing(self.text_keyspacing_width.GetValue(),
+ self.text_keyspacing_height.GetValue())
+ self.umn_legend.set_status(self.choice_status.GetStringSelection())
+ self.umn_legend.set_position(self.choice_position.GetStringSelection())
+ previewcolor = self.previewcolor.GetBackgroundColour()
+ self.umn_legend.get_imagecolor().set_rgbcolor(previewcolor.Red(),
+ previewcolor.Green(), previewcolor.Blue())
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+class Label_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ self.umn_label = parent.umn_label
+
+ # size
+ labelsize= wx.StaticBox(self, 1010, _("Size"), style = 0,
+ name = "Size Box", )
+ box_labelsize = wx.StaticBoxSizer(labelsize, wx.VERTICAL)
+ umn_label_size= self.umn_label.get_size()
+ box_size = wx.BoxSizer(wx.HORIZONTAL)
+ self.text_labelsize = wx.SpinCtrl(self, -1,
+ value=str(umn_label_size), max=10, min=0,
+ name='size', style=wx.SP_ARROW_KEYS)
+ box_size.Add(self.text_labelsize, 2, wx.ALL, 2)
+ box_labelsize.Add(box_size, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # color chooser
+ box_colorStatic = wx.StaticBox(self, 1011, _("Color"), style = 0,
+ name = "color")
+ box_color = wx.StaticBoxSizer(box_colorStatic, wx.VERTICAL)
+ # preview box
+ self.previewcolor = wx.Panel(self, 99, name = 'colorPanel',
+ style = wx.SIMPLE_BORDER | wx.CLIP_CHILDREN)
+ color = self.umn_label.get_color()
+ self.previewcolor.SetBackgroundColour(wx.Colour(color.get_red(),
+ color.get_green(), color.get_blue()))
+ box_color.Add(self.previewcolor, 1, wx.GROW | wx.ALL, 5)
+ # color change button, opens a new color dialog
+ button = wx.Button(self, ID_COLOR_CHANGE, _("Change Color"))
+ button.SetFocus()
+ EVT_BUTTON(self, ID_COLOR_CHANGE, self.OnChangeColor)
+ box_color.Add(button, 1, wx.EXPAND|wx.ALL, 5)
+
+ #get the set type
+ insidetype = self.umn_label.get_type()
+ #create the type selector for fonttype (Bitmap, TrueType)
+ # TODO: Truetype is not supported yet
+ box_typeStatic = wx.StaticBox(self, 1011, _("Type"), style = 0,
+ name = "type")
+ box_type = wx.StaticBoxSizer(box_typeStatic, wx.VERTICAL)
+ sam = []
+ for key in label_font_type:
+ # dont add truetype
+ #if key != 0:
+ sam.append(label_font_type[key])
+ self.choice_type = wx.Choice(self, 40, (80, 50), choices = sam)
+ self.choice_type.SetStringSelection(insidetype)
+ box_type.Add(self.choice_type,0, wx.EXPAND, wx.ALL, 5)
+
+ # Offset
+ offset= wx.StaticBox(self, 1010, _("Offset"), style = 0,
+ name = "Offset Box", )
+ box_offset = wx.StaticBoxSizer(offset, wx.VERTICAL)
+ umn_label_offset = self.umn_label.get_offset()
+ box_offsetX = wx.BoxSizer(wx.HORIZONTAL)
+ box_offsetX.Add(wx.StaticText(self, -1, _("X: ")), 0, wx.ALL, 2)
+ self.text_offsetx = wx.SpinCtrl(self, -1,
+ value=str(umn_label_offset[0]), max=20, min=0,
+ name='offsetX', style=wx.SP_ARROW_KEYS)
+ box_offsetX.Add(self.text_offsetx, 2, wx.ALL, 2)
+ box_offset.Add(box_offsetX, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+ box_offsetY = wx.BoxSizer(wx.HORIZONTAL)
+ box_offsetY.Add(wx.StaticText(self, -1, _("Y: ")), 0, wx.ALL, 2),
+ self.text_offsety = wx.SpinCtrl(self, -1,
+ value=str(umn_label_offset[1]), max=100, min=0,
+ name='offsetY', style=wx.SP_ARROW_KEYS)
+ box_offsetY.Add(self.text_offsety, 2, wx.ALL, 2)
+ box_offset.Add(box_offsetY, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # partials
+ umn_partials = self.umn_label.get_partials()
+ self.choice_partials = wx.RadioBox(self, -1, choices=["True","False"],
+ label='partials', majorDimension=1,
+ name='partials check',
+ size=wx.DefaultSize,
+ style=wx.RA_SPECIFY_ROWS)
+ self.choice_partials.SetStringSelection(str(umn_partials))
+
+ # force
+ umn_force = self.umn_label.get_force()
+ self.choice_force = wx.RadioBox(self, -1, choices=["True","False"],
+ label='force', majorDimension=1,
+ name='force check', size=wx.DefaultSize, style=wx.RA_SPECIFY_ROWS)
+ self.choice_force.SetStringSelection(str(umn_force))
+
+ # buffer
+ buffer = wx.StaticBox(self, 1010, _("Buffer"), style = 0,
+ name = "Buffer Box", )
+ box_buffer = wx.StaticBoxSizer(buffer, wx.VERTICAL)
+ umn_buffer= self.umn_label.get_buffer()
+ box_buffertext = wx.BoxSizer(wx.HORIZONTAL)
+ self.text_buffer = wx.SpinCtrl(self, -1,
+ value=str(umn_buffer), max=10, min=0,
+ name='size', style=wx.SP_ARROW_KEYS)
+ box_buffertext.Add(self.text_buffer, 2, wx.ALL, 2)
+ box_buffer.Add(box_buffertext, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # minfeaturesize
+ minfeaturesize = wx.StaticBox(self, 1010, _("Minfeaturesize"),
+ style = 0, name = "Minfeaturesize Box")
+ box_minfeaturesize = wx.StaticBoxSizer(minfeaturesize, wx.VERTICAL)
+ umn_minfeaturesize= self.umn_label.get_minfeaturesize()
+ box_minfeaturesizetext = wx.BoxSizer(wx.HORIZONTAL)
+ self.text_minfeaturesize = wx.SpinCtrl(self, -1,
+ value=str(umn_minfeaturesize), max=10, min=-1,
+ name='minfeaturesize', style=wx.SP_ARROW_KEYS)
+ box_minfeaturesizetext.Add(self.text_minfeaturesize, 2, wx.ALL, 2)
+ box_minfeaturesize.Add(box_minfeaturesizetext, 0,
+ wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # mindistance
+ mindistance = wx.StaticBox(self, 1010, _("Mindistance"), style = 0,
+ name = "Mindistance Box", )
+ box_mindistance = wx.StaticBoxSizer(mindistance, wx.VERTICAL)
+ umn_mindistance= self.umn_label.get_mindistance()
+ box_mindistancetext = wx.BoxSizer(wx.HORIZONTAL)
+ self.text_mindistance = wx.SpinCtrl(self, -1,
+ value=str(umn_mindistance), max=10, min=-1,
+ name='mindistance', style=wx.SP_ARROW_KEYS)
+ box_mindistancetext.Add(self.text_mindistance, 2, wx.ALL, 2)
+ box_mindistance.Add(box_mindistancetext, 0,
+ wx.ALIGN_RIGHT | wx.ALL, 2)
+
+ # position
+ umn_label_position= self.umn_label.get_position(mode="string")
+ possible_choices = []
+ for key in label_position_type:
+ possible_choices.append(label_position_type[key])
+ self.choice_position = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Position', majorDimension=1,
+ name='position check',
+ size=wx.DefaultSize,
+ style=wx.RA_SPECIFY_ROWS)
+ self.choice_position.SetStringSelection(umn_label_position)
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the Dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+
+ top1 = wx.BoxSizer(wx.HORIZONTAL)
+ top1.Add(box_labelsize,0, wx.EXPAND |wx.ALL, 5)
+ top1.Add(box_color,0, wx.EXPAND |wx.ALL, 5)
+ top1.Add(box_minfeaturesize,0, wx.EXPAND |wx.ALL, 5)
+
+ top2 = wx.BoxSizer(wx.HORIZONTAL)
+ top2.Add(box_type,0,wx.EXPAND |wx.ALL, 5)
+ top2.Add(box_offset,0, wx.EXPAND |wx.ALL, 5)
+ top2.Add(box_mindistance,0, wx.EXPAND |wx.ALL, 5)
+
+ top3 = wx.BoxSizer(wx.HORIZONTAL)
+ top3.Add(self.choice_partials,0, wx.EXPAND |wx.ALL, 5)
+ top3.Add(box_buffer,0, wx.EXPAND |wx.ALL, 5)
+ top3.Add(self.choice_force,0, wx.EXPAND |wx.ALL, 5)
+
+ top.Add(top1, 0, wx.EXPAND)
+ top.Add(top2, 0, wx.EXPAND)
+ top.Add(top3, 0, wx.EXPAND)
+ top.Add(self.choice_position,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def OnChangeColor(self, event):
+ cur = self.umn_label.get_color().get_thubancolor()
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+ self.retcolor = None
+ if dialog.ShowModal() == wx.ID_OK:
+ self.retcolor = dialog.GetColor()
+ dialog.Destroy()
+ if self.retcolor:
+ self.redcolor = int(round(self.retcolor.red*255))
+ self.greencolor = int(round(self.retcolor.green*255))
+ self.bluecolor = int(round(self.retcolor.blue*255))
+ self.previewcolor.SetBackgroundColour(wx.Colour(int(self.redcolor),
+ int(self.greencolor),
+ int(self.bluecolor)))
+ # refresh the colorbox to show the new color
+ self.previewcolor.Refresh()
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.umn_label.set_size(self.text_labelsize.GetValue())
+ self.umn_label.set_offset(self.text_offsetx.GetValue(),
+ self.text_offsety.GetValue())
+ self.umn_label.set_type(self.choice_type.GetStringSelection())
+ if self.choice_partials.GetStringSelection() == "True":
+ self.umn_label.set_partials(True)
+ else:
+ self.umn_label.set_partials(False)
+ previewcolor = self.previewcolor.GetBackgroundColour()
+ self.umn_label.get_color().set_rgbcolor(previewcolor.Red(),
+ previewcolor.Green(), previewcolor.Blue())
+ self.umn_label.set_mindistance(self.text_mindistance.GetValue())
+ self.umn_label.set_minfeaturesize(self.text_minfeaturesize.GetValue())
+ self.umn_label.set_position(self.choice_position.GetStringSelection())
+ self.umn_label.set_buffer(self.text_buffer.GetValue())
+ if self.choice_force.GetStringSelection() == "True":
+ self.umn_label.set_force(True)
+ else:
+ self.umn_label.set_force(False)
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+class Scalebar_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ self.tb_map = parent.canvas.Map()
+ self.umn_scalebar = self.tb_map.extension_umn_mapobj.get_scalebar()
+
+ # color chooser
+ box_colorStatic = wx.StaticBox(self, 1011, _("Color"), style = 0,
+ name = "color")
+ box_color = wx.StaticBoxSizer(box_colorStatic, wx.VERTICAL)
+ # preview box
+ self.previewcolor = wx.Panel(self, 99, name = 'colorPanel',
+ style = wx.SIMPLE_BORDER | wx.CLIP_CHILDREN)
+ color = self.umn_scalebar.get_color()
+ self.previewcolor.SetBackgroundColour(wx.Colour(color.get_red(),
+ color.get_green(), color.get_blue()))
+ box_color.Add(self.previewcolor, 1, wx.GROW | wx.ALL, 5)
+ # color change button, opens a new color dialog
+ button = wx.Button(self, ID_COLOR_CHANGE, _("Change Color"))
+ button.SetFocus()
+ EVT_BUTTON(self, ID_COLOR_CHANGE, self.OnChangeColor)
+ box_color.Add(button, 1, wx.EXPAND|wx.ALL, 5)
+ # show the two color chooser horizontal
+ colorHor = wx.BoxSizer(wx.HORIZONTAL)
+ colorHor.Add(box_color,0, wx.EXPAND |wx.ALL, 5)
+
+ # imagecolor chooser
+ box_imgcolorStatic = wx.StaticBox(self, 1011, _("Image Color"),
+ style = 0, name = "imgcolor")
+ box_imgcolor = wx.StaticBoxSizer(box_imgcolorStatic, wx.VERTICAL)
+ # preview box
+ self.previewimgcolor = wx.Panel(self, 99, name = 'colorPanel',
+ style = wx.SIMPLE_BORDER|wx.CLIP_CHILDREN)
+ color = self.umn_scalebar.get_imagecolor()
+ self.previewimgcolor.SetBackgroundColour(wx.Colour(color.get_red(),
+ color.get_green(), color.get_blue()))
+ box_imgcolor.Add(self.previewimgcolor, 1, wx.GROW | wx.ALL, 5)
+ # color change button, opens a new color dialog
+ button = wx.Button(self, ID_IMGCOLOR_CHANGE, _("Change ImageColor"))
+ button.SetFocus()
+ EVT_BUTTON(self, ID_IMGCOLOR_CHANGE, self.OnChangeImageColor)
+ box_imgcolor.Add(button, 1, wx.EXPAND|wx.ALL, 5)
+ colorHor.Add(box_imgcolor,0, wx.EXPAND |wx.ALL, 5)
+
+ # create the intervals
+ intervalsStatic = wx.StaticBox(self, 1010, _("Intervals"), style = 0,
+ name = "Intervals Box", )
+ box_intervals = wx.StaticBoxSizer(intervalsStatic, wx.VERTICAL)
+ umn_scalebar_intervals = self.umn_scalebar.get_intervals()
+ self.text_intervals = wx.SpinCtrl(self, -1,
+ value=str(umn_scalebar_intervals), max=100, min=0,
+ name='intervals', style=wx.SP_ARROW_KEYS)
+ box_intervals.Add(self.text_intervals, 0, wx.ALIGN_RIGHT | wx.ALL, 2)
+ hori2 = wx.BoxSizer(wx.HORIZONTAL)
+ hori2.Add(box_intervals,0, wx.EXPAND |wx.ALL, 5)
+
+ #style
+ umn_scalebar_style= self.umn_scalebar.get_style()
+ possible_choices = []
+ for key in scalebar_style_type:
+ possible_choices.append(scalebar_style_type[key])
+ self.choice_style = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Style', majorDimension=1,
+ name='style check', size=wx.DefaultSize, style=wx.RA_SPECIFY_ROWS)
+ self.choice_style.SetSelection(umn_scalebar_style)
+ hori2.Add(self.choice_style, 1, wx.EXPAND|wx.ALL, 5)
+
+ #create size settings
+ try:
+ insidetxt = self.umn_scalebar.get_size()
+ except:
+ insidetxt = (0,0)
+ # create the Size Box
+ staticSize = wx.StaticBox(self, -1, _("Size"), style = 0,
+ name="sizeBox")
+ box_size = wx.StaticBoxSizer(staticSize, wx.HORIZONTAL)
+
+ box_sizepartWidth = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartWidth.Add(wx.StaticText(self, -1, _("Width: ")), 0, wx.ALL, 4)
+ self.text_width = wx.TextCtrl(self, -1, str(insidetxt[0]))
+ box_sizepartWidth.Add(self.text_width, 2, wx.ALL, 4)
+ box_size.Add(box_sizepartWidth, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
+ box_sizepartHeight = wx.BoxSizer(wx.HORIZONTAL)
+ box_sizepartHeight.Add(wx.StaticText(self, -1, _("Height: ")), 0,
+ wx.ALL, 4)
+ self.text_height = wx.TextCtrl(self, -1, str(insidetxt[1]))
+ box_sizepartHeight.Add(self.text_height, 2, wx.ALL, 4)
+ box_size.Add(box_sizepartHeight, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
+
+ # status
+ umn_scalebar_status= self.umn_scalebar.get_status(mode="string")
+ possible_choices = []
+ for key in legend_status_type:
+ possible_choices.append(scalebar_status_type[key])
+ self.choice_status = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Status', majorDimension=1,
+ name='status check', size=wx.DefaultSize, style=wx.RA_SPECIFY_ROWS)
+ self.choice_status.SetStringSelection(umn_scalebar_status)
+
+ # position
+ umn_scalebar_position= self.umn_scalebar.get_position(mode="string")
+ possible_choices = []
+ for key in scalebar_position_type:
+ possible_choices.append(scalebar_position_type[key])
+ self.choice_position = wx.RadioBox(self, -1, choices=possible_choices,
+ label='Position', majorDimension=1,
+ name='position check', size=wx.DefaultSize,
+ style=wx.RA_SPECIFY_ROWS)
+ self.choice_position.SetStringSelection(umn_scalebar_position)
+
+ #get the set unittype
+ insideunit = self.umn_scalebar .get_units()
+ #create the Unittype selector
+ box_unitsStatic = wx.StaticBox(self, -1, _("Unit Type"), style = 0,
+ name = "unittype")
+ box_units = wx.StaticBoxSizer(box_unitsStatic, wx.VERTICAL)
+ sam = []
+ for key in unit_type:
+ sam.append(unit_type[key])
+ self.choice_units = wx.Choice(self, 40, (80, 50), choices = sam)
+ self.choice_units.SetStringSelection(insideunit)
+ box_units.Add(self.choice_units,0, wx.EXPAND, wx.ALL, 5)
+
+ # button for label
+ labelbutton = wx.Button(self, ID_LABEL_CHANGE, _("Change Label"))
+ EVT_BUTTON(self, ID_LABEL_CHANGE, self.OnChangeLabel)
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ button.SetFocus()
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+ top.Add(colorHor,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(hori2, 1, wx.EXPAND|wx.ALL, 5)
+ top.Add(box_size, 1, wx.EXPAND|wx.ALL, 5)
+ top.Add(self.choice_status,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(self.choice_position,0, wx.EXPAND |wx.ALL, 5)
+ top.Add(box_units, 1, wx.EXPAND|wx.ALL, 5)
+ top.Add(labelbutton, 0, wx.EXPAND|wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ top.Fit(self)
+
+ def OnChangeLabel(self, event):
+ # set the umn_label for scalebar so the Label_Dialog can be used
+ self.umn_label = self.umn_scalebar.get_label()
+ dialog = Label_Dialog(self, -1, "Scalbar Label Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE
+ )
+ dialog.CenterOnScreen()
+ if dialog.ShowModal() == wx.ID_OK:
+ return
+ dialog.Destroy()
+
+ def OnChangeImageColor(self, event):
+ cur = self.umn_scalebar.get_imagecolor().get_thubancolor()
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+ self.retcolor = None
+ if dialog.ShowModal() == wx.ID_OK:
+ self.retcolor = dialog.GetColor()
+ dialog.Destroy()
+ if self.retcolor:
+ self.redcolor = int(round(self.retcolor.red*255))
+ self.greencolor = int(round(self.retcolor.green*255))
+ self.bluecolor = int(round(self.retcolor.blue*255))
+ self.previewimgcolor.SetBackgroundColour(wx.Colour(int(self.redcolor),
+ int(self.greencolor),
+ int(self.bluecolor)))
+ # refresh the colorbox to show the new color
+ self.previewimgcolor.Refresh()
+
+ def OnChangeColor(self, event):
+ cur = self.umn_scalebar.get_color().get_thubancolor()
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+ self.retcolor = None
+ if dialog.ShowModal() == wx.ID_OK:
+ self.retcolor = dialog.GetColor()
+ dialog.Destroy()
+ if self.retcolor:
+ self.redcolor = int(round(self.retcolor.red*255))
+ self.greencolor = int(round(self.retcolor.green*255))
+ self.bluecolor = int(round(self.retcolor.blue*255))
+ self.previewcolor.SetBackgroundColour(wx.Colour(int(self.redcolor),
+ int(self.greencolor),
+ int(self.bluecolor)))
+ # refresh the colorbox to show the new color
+ self.previewcolor.Refresh()
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.umn_scalebar.set_status(self.choice_status.GetStringSelection())
+ self.umn_scalebar.set_units(self.choice_units.GetStringSelection())
+ self.umn_scalebar.set_intervals(self.text_intervals.GetValue())
+ self.umn_scalebar.set_style(self.choice_style.GetSelection())
+ self.umn_scalebar.set_position(self.choice_position.GetStringSelection())
+ self.umn_scalebar.set_size(int(self.text_width.GetValue()),
+ int(self.text_height.GetValue()))
+
+ previewcolor = self.previewcolor.GetBackgroundColour()
+ self.umn_scalebar.get_color().set_rgbcolor(previewcolor.Red(),
+ previewcolor.Green(), previewcolor.Blue())
+ previewimgcolor = self.previewimgcolor.GetBackgroundColour()
+ self.umn_scalebar.get_imagecolor().set_rgbcolor(previewimgcolor.Red(),
+ previewimgcolor.Green(), previewimgcolor.Blue())
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+
+class Metadata_CustomDataTable(grid.PyGridTableBase):
+ """
+ creates a custum Grid.
+
+ copied from the wx. demo.
+ """
+ def __init__(self, data):
+ gridPyGridTableBase.__init__(self)
+
+ self.colLabels = ['ID', 'Description']
+ self.dataTypes = [wx.GRID_VALUE_STRING,
+ wx.GRID_VALUE_STRING
+ ]
+
+ if data:
+ self.data = data
+ else:
+ self.data = [["",""]] #--------------------------------------------------
+ # required methods for the grid.PyGridTableBase interface
+
+ def GetNumberRows(self):
+ return len(self.data) + 1
+
+ def GetNumberCols(self):
+ return len(self.data[0])
+
+ def IsEmptyCell(self, row, col):
+ try:
+ return not self.data[row][col]
+ except IndexError:
+ return true
+
+ # Get/Set values in the table. The Python version of these
+ # methods can handle any data-type, (as long as the Editor and
+ # Renderer understands the type too,) not just strings as in the
+ # C++ version.
+ def GetValue(self, row, col):
+ try:
+ return self.data[row][col]
+ except IndexError:
+ return ''
+
+ def SetValue(self, row, col, value):
+ try:
+ self.data[row][col] = value
+ except IndexError:
+ # add a new row
+
+ self.data.append([''] * self.GetNumberCols())
+ self.SetValue(row, col, value)
+
+ # tell the grid we've added a row
+ msg = grid.GridTableMessage(self, # The table
+ wx.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it
+ 1) # how many
+
+ self.GetView().ProcessTableMessage(msg)
+
+ #--------------------------------------------------
+ # Some optional methods
+
+ # Called when the grid needs to display labels
+ def GetColLabelValue(self, col):
+ return self.colLabels[col]
+
+ # Called to determine the kind of editor/renderer to use by
+ # default, doesn't necessarily have to be the same type used
+ # natively by the editor/renderer if they know how to convert.
+ def GetTypeName(self, row, col):
+ return self.dataTypes[col]
+
+ # Called to determine how the data can be fetched and stored by the
+ # editor and renderer. This allows you to enforce some type-safety
+ # in the grid.
+ def CanGetValueAs(self, row, col, typeName):
+ colType = self.dataTypes[col].split(':')[0]
+ if typeName == colType:
+ return true
+ else:
+ return False
+
+ def CanSetValueAs(self, row, col, typeName):
+ return self.CanGetValueAs(row, col, typeName)
+
+
+class Metadata_TableGrid(grid.Grid):
+ def __init__(self, parent, data):
+ grid.Grid.__init__(self, parent, -1)
+
+ self.table = Metadata_CustomDataTable(data)
+
+ # The second parameter means that the grid is to take ownership of the
+ # table and will destroy it when done. Otherwise you would need to keep
+ # a reference to it and call it's Destroy method later.
+ self.SetTable(self.table, true)
+
+ self.SetRowLabelSize(0)
+ self.SetColMinimalWidth(0,180)
+ self.SetColSize(0,180)
+ self.SetColMinimalWidth(1,250)
+ self.SetColSize(1,250)
+ self.SetMargins(0,0)
+ EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick)
+
+ def get_table(self):
+ return self.table
+
+ # I do this because I don't like the default behaviour of not starting the
+ # cell editor on double clicks, but only a second click.
+ def OnLeftDClick(self, evt):
+ if self.CanEnableCellControl():
+ self.EnableCellEditControl()
+
+
+class Metadata_Dialog(wx.Dialog):
+
+ def __init__(self, parent, ID, title,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=wx.DEFAULT_DIALOG_STYLE):
+
+ # initialize the Dialog
+ wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
+
+ # get the web object
+ if hasattr(parent,"umn_metadata"):
+ self.umn_metadata = parent.umn_metadata
+ else:
+ self.tb_map = parent.canvas.Map()
+ self.umn_metadata = self.tb_map.extension_umn_mapobj.get_metadata()
+
+
+ # at all items to the dataset
+ self.grid = Metadata_TableGrid(self, self.umn_metadata.get_metadata())
+
+ #buttons
+ box_buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ button.SetFocus()
+ box_buttons.Add(button, 0, wx.ALL, 5)
+ #set the button funcitons
+ EVT_BUTTON(self, wx.ID_OK, self.OnOK)
+ EVT_BUTTON(self, wx.ID_CANCEL, self.OnCancel)
+
+ # compose the dialog
+ top = wx.BoxSizer(wx.VERTICAL)
+ top.Add(self.grid, 1, wx.GROW|wx.ALL, 5)
+ top.Add(box_buttons, 0, wx.ALIGN_RIGHT)
+
+ # final layout settings
+ self.SetSizer(top)
+ #top.Fit(self)
+
+ def OnItemActivated(self, event):
+ self.currentItem = event.m_itemIndex
+
+ def OnDoubleClick(self, event):
+ print "OnDoubleClick" +self.list.GetItemText(self.currentItem)
+ event.Skip()
+
+ def OnSize(self, event):
+ w,h = self.GetClientSizeTuple()
+ self.list.SetDimensions(0, 0, w, h)
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+
+ def end_dialog(self, result):
+ self.result = result
+ if self.result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ # added all metadatas to the mapobj,
+ # first remove the old ones
+ self.umn_metadata.remove_allmetadata()
+ for x in range(self.grid.get_table().GetNumberRows()-2,-1, -1):
+ if self.grid.get_table().GetValue(x,0):
+ self.umn_metadata.add_metadata(str(self.grid.get_table().GetValue(x,0)),\
+ str(self.grid.get_table().GetValue(x,1)))
+
+ self.result ="OK"
+ self.end_dialog(self.result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+
+
+
+def metadatasettings(context):
+ win = Metadata_Dialog(context.mainwindow, -1, "Metadata Settings",
+ size=wx.Size(450, 250),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+
+def scalebarsettings(context):
+ win = Scalebar_Dialog(context.mainwindow, -1, "Scalebar Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+def mapsettings(context):
+ win = Map_Dialog(context.mainwindow, -1, "Map Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+def outputformatsettings(context):
+ win = OutputFormat_Dialog(context.mainwindow, -1, "OutputFormat Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+def websettings(context):
+ win = Web_Dialog(context.mainwindow, -1, "Web Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+def layersettings(context):
+ win = Layer_Dialog(context.mainwindow, -1, "Layer Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+def legendsettings(context):
+ win = Legend_Dialog(context.mainwindow, -1, "Legend Settings",
+ size=wx.Size(350, 200),
+ style = wx.DEFAULT_DIALOG_STYLE)
+ win.CenterOnScreen()
+ val = win.ShowModal()
+
+# TODO: Maybe can be imported from another class
+# check if an mapobj exists, to control the menuitem is available or not
+def _has_umn_mapobj(context):
+ """Return true if a umn_mapobj exists"""
+ return hasattr(context.mainwindow.canvas.Map(), "extension_umn_mapobj")
+
+def _has_umn_mapobj_and_selectedlayer(context):
+ """Return true if a umn_mapobj exists"""
+ # temporary disabled
+ #return False
+ if context.mainwindow.has_selected_layer():
+ return hasattr(context.mainwindow.canvas.Map(), "extension_umn_mapobj")
+ else:
+ return False
+
+# ###################################
+#
+# Hook in MapServer Extension into Thuban
+#
+# ###################################
+
+# find the extensions menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu("experimental",
+ _("Experimenta&l"))
+# find the extension menu and add a new submenu if found
+mapserver_menu = experimental_menu.FindOrInsertMenu("mapserver",
+ _("&MapServer"))
+
+# find the MapServer menu and add a new submenu if found
+mapserver_edit_menu = mapserver_menu.FindOrInsertMenu("edit_mapfile",
+ _("&Edit mapfile"), \
+ after = "import_layer_from_mapfile")
+
+# register the new command (Map Settings Dialog)
+registry.Add(Command("Map Settings", _("Map"), mapsettings,
+ helptext = _("Edit the Map Setting"), \
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Map Settings")
+
+
+# register the new command (Map Settings Dialog)
+registry.Add(Command("Web Settings", _("Web"),
+ websettings,
+ helptext = _("Edit the Web Setting"), \
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Web Settings")
+
+# register the new command (Layer Settings Dialog)
+registry.Add(Command("Layer Settings", _("Layer"),
+ layersettings,
+ helptext = _("Edit the Layer Setting of the aktive Layer"), \
+ sensitive = _has_umn_mapobj_and_selectedlayer))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Layer Settings")
+
+# register the new command (Legend Settings Dialog)
+registry.Add(Command("Legend Settings", _("Legend"),
+ legendsettings,
+ helptext = _("Edit the Legend Setting"), \
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Legend Settings")
+
+# register the new command (Scalebar Settings Dialog)
+registry.Add(Command("Scalebar Settings", _("Scalebar"),
+ scalebarsettings,
+ helptext = _("Edit the Scalebar Setting"), \
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Scalebar Settings")
+
+# register the new command (Scalebar Settings Dialog)
+registry.Add(Command("Metadata Settings", _("Metadata"),
+ metadatasettings,
+ helptext = _("Edit the Metadata Setting"), \
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_edit_menu.InsertItem("Metadata Settings")
+
+
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_import.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_import.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/mf_import.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,762 @@
+# -*- coding:latin1 -*-
+# Copyright (C) 2004 by Intevation GmbH
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+This module extends Thuban with the possibility to handle
+UMN MapServer mapfiles.
+"""
+
+__version__ = "$Revision: 2719 $"
+# $Source$
+# $Id: mf_import.py 2719 2007-01-08 16:30:29Z dpinte $
+
+
+
+# ###################################
+#
+# import necessary modules
+#
+# ###################################
+
+import os, re
+
+from mapscript import mapObj
+
+import wx
+
+# use _() already now for all strings that may later be translated
+from Thuban import _
+
+# Thuban has named commands which can be registered in the central
+# instance registry.
+from Thuban.UI.command import registry, Command
+
+# The instance of the main menu of the Thuban application
+from Thuban.UI import mainwindow
+
+# The layer an projection from Thuban
+from Thuban.Model.layer import Layer, RasterLayer
+from Thuban.Model.proj import Projection
+
+# needed to add the new menu
+from Thuban.UI.mainwindow import main_menu
+
+from Thuban.Model.classification import ClassGroupSingleton, \
+ ClassGroupRange, \
+ ClassGroupProperties, \
+ ClassGroupDefault
+
+from Thuban.Model.range import Range
+
+# The Thuban color objects
+from Thuban.Model.color import Transparent
+
+# import Map Object for the Mapfile
+from mapfile import MF_Map
+
+# ###################################
+#
+# Mainpart of the Extension
+#
+# ###################################
+from Thuban.Model.layer import BaseLayer
+class AnnotationLayer(BaseLayer):
+ """
+ Class to show AnnontationLayer in Thuban.
+ This Class is temporary and has only the task
+ to indicate the layer in the layerlist.
+ """
+ def __init__(self, title, data, visible = False, projection = None):
+
+ BaseLayer.__init__(self, title,
+ visible = visible,
+ projection = projection)
+ self.store = None
+ self.SetShapeStore(data)
+
+ def SetShapeStore(self, store):
+ self.store = store
+
+ def ShapeStore(self):
+ return self.store
+
+ def ShapeType(self):
+ """Return the type of the shapes in the layer.
+ """
+ return "annotation"
+
+ def BoundingBox(self):
+ """Return the layer's bounding box in the intrinsic coordinate system.
+
+ If the layer has no shapes, return None.
+ """
+ return self.store.BoundingBox()
+
+ def LatLongBoundingBox(self):
+ """Return the layer's bounding box in lat/long coordinates.
+
+ Return None, if the layer doesn't contain any shapes.
+ """
+ bbox = self.BoundingBox()
+ if bbox is not None and self.projection is not None:
+ bbox = self.projection.InverseBBox(bbox)
+ return bbox
+
+
+def set_projection_to_tb(tb_con, mapobj):
+ """
+ Helpfunction to set the projection in thuban.
+
+ Parameters:
+ tb_con -- The thuban conext (mapobj or layerobj)
+ mapobj -- The mapobject (from mapscript)
+ """
+ if (mapobj.get_projection().get_params() != None):
+ projparams = mapobj.get_projection().get_params()
+ # check if it is an latlong projection, becaues one
+ # more parameter is needed in that case
+ addtometer = False
+ for param in projparams:
+ projkey = param.split("=")
+ if projkey[0] == "proj":
+ if projkey[1] == "latlong":
+ addtometer = True
+ if projkey[0] == "to_meter":
+ addtometer = False
+ if addtometer == True:
+ projparams.append("to_meter=0.017453")
+ tb_con.SetProjection(Projection(projparams))
+ if mapobj.get_projection().get_epsgcode() != None:
+ projepsg = mapobj.get_projection().get_epsgproj()
+ tb_con.SetProjection(projepsg)
+
+def create_rangeexpression(mapexprstr):
+ """
+ create a expressionstring in thuban style from an given
+ mapfile expressionstring
+
+ mapexprstr = the expressionstring from the mapfile
+ """
+ attribut_expr = "\[\w+\]"
+ attribut = re.compile(attribut_expr)
+ operator_expr = ">=|<=|<|>|="
+ operator = re.compile(operator_expr)
+ #only and now supported
+ link_expr = "AND"
+ link = re.compile(link_expr)
+ oneexpr = "\s*\[\w+\]\s*>*<*=*\s*\w+"
+ theexpr = re.compile(oneexpr)
+
+ # init the string variables to build the string later
+ thestring = ""
+ strbegin = None
+ strmin = None
+ strmax = None
+ strend = None
+
+ link_result = link.findall(mapexprstr)
+ attr = attribut.findall(mapexprstr)
+ if len(link_result) == 0 and len(attr) == 1:
+ strattr = attr[0][1:-1]
+ expression = theexpr.findall(mapexprstr)
+ if expression:
+ operator_result = operator.search(mapexprstr)
+ if operator_result.group(0) == ">=":
+ strbegin = "["
+ strmin = operator_result.string[operator_result.start()+2:].replace(" ","")
+ strmax = "oo"
+ strend = "]"
+ elif operator_result.group(0) == "<=":
+ strbegin = "["
+ strmin = "-oo"
+ strmax = operator_result.string[operator_result.start()+2:].replace(" ","")
+ strend = "]"
+ elif operator_result.group(0) == ">":
+ strbegin = "]"
+ strmin = operator_result.string[operator_result.start()+1:].replace(" ","")
+ strmax = "oo"
+ strend = "]"
+ elif operator_result.group(0) == "<":
+ strbegin = "["
+ strmin = "-oo"
+ strmax = operator_result.string[operator_result.start()+1:].replace(" ","")
+ strend = "["
+ elif operator_result.group(0) == "=":
+ # create a singleton, not implemented yet
+ errorstring = "singleton creation not implemented yet"
+ else:
+ errorstring = "no operator found"
+ else:
+ errorstring = "no expression found"
+ elif len(link_result) == 1:
+ if attr[0] == attr[1]:
+ strattr = attr[0][1:-1]
+ first_expr,second_expr = mapexprstr.split("AND")
+ oneexpr_result = theexpr.findall(mapexprstr)
+ operator1_result = operator.search(first_expr)
+ operator2_result = operator.search(second_expr)
+ errorstring = "operators are wrong"
+ if operator1_result.group(0)[0] == "<" and \
+ operator2_result.group(0)[0] == ">":
+ optemt = operator1_result
+ operator1_result = operator2_result
+ operator2_result = optemt
+ if operator1_result.group(0) == ">=":
+ strbegin = "["
+ strmin = operator1_result.string[operator1_result.start()+2:].replace(" ","")
+ elif operator1_result.group(0) == ">":
+ strbegin = "]"
+ strmin = operator1_result.string[operator1_result.start()+1:].replace(" ","")
+ if operator2_result.group(0) == "<=":
+ strend = "]"
+ strmax = operator2_result.string[operator2_result.start()+2:].replace(" ","")
+ elif operator2_result.group(0) == "<" and operator1_result != ">" :
+ strend = "["
+ strmax = operator2_result.string[operator2_result.start()+1:].replace(" ","")
+ if strmax < strmin:
+ errorstring = "values are wrong"
+ strbegin = None
+ else:
+ errorstring = "Attributes not equal"
+ elif len(link_result) == 0:
+ errorstring = "Link expression not supported"
+ else:
+ errorstring = "More then two expressions"
+
+ #create the expression thestring
+ if strbegin and strmin and strmax and strend:
+ thestring = strbegin +strmin+";"+strmax + strend
+ return (strattr, thestring)
+ else:
+ return (None,errorstring)
+
+def add_annotationlayer(context, tb_map, mapobj, maplayer):
+ """
+ add a polygonlayer to thuban
+
+ tb_map = context.mainwindow.canvas.Map()
+
+ mapobj = the Mapobject created from the mapfile
+
+ maplayer = layer obj to add to thuban
+ """
+ filepath = mapobj.get_mappath()
+ layertitle = maplayer.get_name()
+ if maplayer.get_data():
+ if os.path.isabs(maplayer.get_data()):
+ filename = maplayer.get_data() +".shp"
+ else:
+ filename = os.path.join(filepath, mapobj.get_shapepath(), \
+ maplayer.get_data())
+ filename = filename + ".shp"
+ # Normalize the pathname by collapses
+ # redundant separators and up-level references
+ filename = os.path.normpath(filename)
+ else:
+ context.mainwindow.RunMessageBox(_('Error Loading Layer'),
+ _("no shp file definied, maybe used a feature obj '%s'.") % layertitle)
+ # try to open the layer
+ try:
+ store = context.application.Session().OpenShapefile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(_('Open Shapepath'),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ # added an annotation layer as empty layer to thuban
+ # because thuban don't supports annotation.
+ layertitle = maplayer.get_name()
+ annotationlayer = AnnotationLayer(layertitle,store)
+ # associate a copy of the maplayer object to the layer in thuban.
+ annotationlayer.extension_umn_layerobj = maplayer
+ tb_map.AddLayer(annotationlayer)
+
+
+def add_rasterlayer(context, tb_map, mapobj, maplayer):
+ """
+ add a rasterlayer to thuban
+
+ tb_map = context.mainwindow.canvas.Map()
+
+ mapobj = the Mapobject created from the mapfile
+
+ maplayer = layer obj to add to thuban
+ """
+ imgpath = maplayer.get_data()
+ shapepath = mapobj.get_shapepath()
+ filepath = mapobj.get_mappath()
+ layertitle = maplayer.get_name()
+ # if there is no imagepath defined, the Raster Layer could not load
+ if imgpath == None:
+ context.mainwindow.RunMessageBox(_('Error Loading Raster Layer'),
+ _("Can't open the rasterlayer '%s'.") % layertitle)
+ else:
+ if os.path.isabs(imgpath):
+ filename = imgpath
+ else:
+ filename = os.path.join(filepath, shapepath,imgpath)
+ # Normalize the pathname by collapses
+ # redundant separators and up-level references
+ filename = os.path.normpath(filename)
+ rasterlayer = RasterLayer(layertitle, filename)
+ # set the visible status
+ rasterlayer.SetVisible(maplayer.get_status())
+ #add the projection if exists
+ set_projection_to_tb(rasterlayer, maplayer)
+
+ # associate a copy of the maplayer object to the layer in thuban.
+ rasterlayer.extension_umn_layerobj = maplayer
+ tb_map.AddLayer(rasterlayer)
+
+
+def add_polygonlayer(context, tb_map, mapobj, maplayer):
+ """
+ add a polygonlayer to thuban
+
+ tb_map = context.mainwindow.canvas.Map()
+
+ mapobj = the Mapobject created from the mapfile
+
+ maplayer = layer obj to add to thuban
+ """
+ filepath = mapobj.get_mappath()
+ layertitle = maplayer.get_name()
+ if maplayer.get_data():
+ if os.path.isabs(maplayer.get_data()):
+ filename = maplayer.get_data() +".shp"
+ else:
+ filename = os.path.join(filepath, mapobj.get_shapepath(), \
+ maplayer.get_data())
+ filename = filename + ".shp"
+ # Normalize the pathname by collapses
+ # redundant separators and up-level references
+ filename = os.path.normpath(filename)
+ else:
+ context.mainwindow.RunMessageBox(_('Error Loading Layer'),
+ _("no shp file definied, maybe used a feature obj '%s'.") % layertitle)
+ # try to open the layer
+ try:
+ store = context.application.Session().OpenShapefile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ context.mainwindow.RunMessageBox(_('Open Shapepath'),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ # create a new layer which will be added to thuban later
+ layer = Layer(layertitle, store)
+ # all classes of the maplayer
+ map_clazzes = maplayer.get_classes()
+ # number of layers loaded vom maplayer
+ map_numclazzes = len(map_clazzes)
+ # defaultclazzset is necessary to know if a default class is set
+ # in thuban. if is not and there are more them one class in the
+ # mapfile the colors of the default layer in thuban musst
+ # set to Transparence
+ defaultclazzset = None
+
+ # create a class in thuban for every class in the maplayer
+ for map_clazznr in range(0, map_numclazzes, 1):
+ # define the color
+ map_clazz = map_clazzes[map_clazznr]
+ layer_style = map_clazz.get_styles()[0]
+ clazz_name = map_clazz.get_name()
+ clazz = layer.GetClassification()
+ prop = ClassGroupProperties()
+ # set the layerprojection if given
+ # TODO check this, becaus it is not working correctly
+ # set_projection_to_tb(layer, maplayer)
+
+ # if outline color is defined use it else set transparent
+ if layer_style.get_outlinecolor():
+ tb_color = layer_style.get_outlinecolor().get_thubancolor()
+ prop.SetLineColor(tb_color)
+ else:
+ prop.SetLineColor(Transparent)
+ # if color is defined use it as fillcolor
+ # but if the layer type is line use the color as linecolor
+ if layer_style.get_color():
+ tb_color = layer_style.get_color().get_thubancolor()
+ if maplayer.get_type() == 'line':
+ prop.SetLineColor(tb_color)
+ else:
+ prop.SetFill(tb_color)
+ else:
+ prop.SetFill(Transparent)
+
+ #set size for the line
+ if ((maplayer.get_type() == 'polygon') or
+ (maplayer.get_type() == 'line')):
+ if layer_style.get_size():
+ prop.SetLineWidth(layer_style.get_size())
+
+ # generate special expression classes to show in thuban
+ # not all possibilities from the MapServer are supported now
+ # supporteed:
+ # String comparisons
+ # not supported:
+ # Regular expressions
+ # Logical expressions
+ expressionstring = map_clazz.get_expressionstring()
+ if (((map_numclazzes == 1) & (not expressionstring)) or
+ ((map_numclazzes > 1) & (expressionstring == None)) or
+ (expressionstring == '/./')):
+ if clazz_name == None:
+ clazz_name = ""
+ new_group = ClassGroupDefault(props = prop, label = clazz_name)
+ new_group.SetVisible(map_clazz.get_status())
+ clazz.SetDefaultGroup(new_group)
+ defaultclazzset = True
+ # break, because alle classes behind the one which definies the
+ # default will be ignored by mapserver. See sample
+ # TODO: if possible set it as invisible class in thuban, but
+ # show the parts of that class as default.
+ # not possible at the moment ?
+ break
+
+ # this is the String comparison.
+ # the expressionstring is enclosed by the ' or " indications
+ elif ((expressionstring[0] == "'") or
+ (expressionstring[0] == '"')):
+ expressionclassitem = maplayer.get_classitem().upper()
+ layer.SetClassificationColumn(expressionclassitem)
+ try:
+ theexpression = int(expressionstring[1:-1])
+ except:
+ theexpression = expressionstring[1:-1]
+ if clazz_name == None:
+ clazz_name = str("")
+ new_group = ClassGroupSingleton(value = theexpression,
+ props = prop,
+ label = clazz_name)
+ new_group.SetVisible(map_clazz.get_status())
+ clazz.AppendGroup(new_group)
+ elif (expressionstring[0] == "("):
+ expressionclassitem, thubanexpr \
+ = create_rangeexpression(expressionstring[1:-1])
+ if expressionclassitem == None:
+ if clazz_name == None:
+ clazz_showtxt = "Nr. " + str(map_clazznr+1)
+ else:
+ clazz_showtxt = clazz_name
+ context.mainwindow.RunMessageBox(_('Error Loading Expression'), \
+ _("%s \n" + \
+ "Can't load the Expression from layer \n" + \
+ "Layer: %s ; Class: %s\n" + \
+ "Expression: %s")\
+ %(thubanexpr, layer.title, clazz_showtxt, expressionstring[1:-1]) )
+ else:
+ layer.SetClassificationColumn(expressionclassitem)
+ if clazz_name == None:
+ clazz_name = str("")
+ expressionrange = Range(thubanexpr)
+ new_group = ClassGroupRange(expressionrange,
+ props = prop,
+ label = clazz_name)
+ new_group.SetVisible(map_clazz.get_status())
+ clazz.AppendGroup(new_group)
+
+ else:
+ new_group = ClassGroupSingleton(props = prop,label = clazz_name)
+ new_group.SetVisible(map_clazz.get_status())
+ clazz.AppendGroup(new_group)
+
+ # if there is no default layer set,
+ # the color and linecolor will set as Transparent.
+ if (not defaultclazzset):
+ proptp = ClassGroupProperties()
+ proptp.SetLineColor(Transparent)
+ new_group = ClassGroupDefault(props = proptp)
+ clazz.SetDefaultGroup(new_group)
+ defaultclazzset = None
+
+ # set the visible status
+ layer.SetVisible(maplayer.get_status())
+ #add the projection if exists
+ set_projection_to_tb(layer, maplayer)
+
+ # associate a copy of the maplayer object to the layer in thuban.
+ layer.extension_umn_layerobj =maplayer
+ #add the layer into thuban
+ tb_map.AddLayer(layer)
+
+
+def select_layer2import(context, mapobj):
+ """
+ shows a dialog to select the layers to import.
+
+ mapobj = the Mapobject created from the mapfile
+ """
+ # Show number of Layer found in file
+ numlayers = len(mapobj.get_layers())
+ if numlayers == 0:
+ context.mainwindow.RunMessageBox(_('Loading Layer'),
+ _("No Layer found."))
+ else:
+ context.mainwindow.RunMessageBox(_('Loading Layer'),
+ _("%s Layer loaded from file.") % numlayers)
+ # Show a dialog to select layers to load into thuban only
+ lst = []
+ selectedlayer = []
+ numlayers = len(mapobj.get_layers())
+ for layernr in range(0, numlayers,1):
+ lst.append(mapobj.get_layers()[layernr].get_name() +
+ " (" + mapobj.get_layers()[layernr].get_type() +")" )
+
+ dlgsize = (300,130+len(lst)*20)
+ if dlgsize[1] >= 300:
+ dlgsize = (300,300)
+ dlg = wx.MultipleChoiceDialog(context.mainwindow,
+ "Select the layers from the\n" +
+ "list to load into thuban.\n" +
+ "annotation not supported !",
+ "Select Layer.", lst, size = dlgsize)
+ if (dlg.ShowModal() == wx.ID_OK):
+ selectedlayer = dlg.GetValue()
+ return selectedlayer
+
+def import_layer_from_mapfile(context):
+ """
+ Import only the layers which are selectes from a mapfile
+ """
+ # open a dialog to select the mapfile to import
+ dlg = wx.FileDialog(context.mainwindow,
+ _("Select MapFile file"), ".", "",
+ _("UMN MapServer Mapfiles (*.map)|*.map|") +
+ _("All Files (*.*)|*.*"),
+ wx.OPEN|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ dlg.Destroy()
+ else:
+ return
+
+ # Parse mapfile
+ mapobj = parse_mapfile(filename)
+
+ # Show number of Layer found in file
+ numlayers = len(mapobj.get_layers())
+ if numlayers == 0:
+ context.mainwindow.RunMessageBox(_('Loading Layer'),
+ _("No Layer found."))
+ else:
+ context.mainwindow.RunMessageBox(_('Loading Layer'),
+ _("%s Layer loaded from file.") % numlayers)
+ # Show a dialog to select layers to load into thuban only
+ # if the mapfile contains any layer
+ if numlayers != 0:
+ selectedlayer = select_layer2import(context,mapobj)
+ else:
+ selectedlayer = []
+
+def import_layer_from_mapfile(context):
+ """
+ import layers from a mapfile
+ """
+ # open a dialog to select the mapfile to import from
+ dlg = wx.FileDialog(context.mainwindow,
+ _("Select MapFile file"), ".", "",
+ _("UMN MapServer Mapfiles (*.map)|*.map|") +
+ _("All Files (*.*)|*.*"),
+ wx.OPEN|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ dlg.Destroy()
+ else:
+ return
+
+ # Parse mapfile
+ mapobj = parse_mapfile(filename)
+ oldmapobj = context.mainwindow.canvas.Map().extension_umn_mapobj
+
+ # shows a dialog to select layers to import
+ selectedlayer = select_layer2import(context,mapobj)
+
+ # counter to show the numer of layer loaded into Tuban
+ layer_count = 0
+ # import settings to thuban only if one layer is selected
+ if len(selectedlayer) != 0:
+ # thuban map context
+ tb_map = context.mainwindow.canvas.Map()
+ # Check for each Layer if it is possible to show in Thuban
+ for layernr in selectedlayer:
+ maplayer = mapobj.get_layers()[layernr]
+
+ #check if rasterlayer type
+ if maplayer.get_type() == 'raster':
+ add_rasterlayer(context, tb_map, mapobj, maplayer)
+ layer_count += 1
+
+ #check if polygonlayer type
+ if ((maplayer.get_type() == 'polygon') or
+ (maplayer.get_type() == 'line') or
+ (maplayer.get_type() == 'circle') or
+ (maplayer.get_type() == 'point')):
+ add_polygonlayer(context, tb_map, mapobj, maplayer)
+ layer_count += 1
+
+ if (maplayer.get_type() == 'annotation'):
+ add_annotationlayer(context, tb_map, mapobj, maplayer)
+
+ # show a message how many layer were loaded into thuban
+ # if the number of layers is not null
+ if layer_count != 0:
+ context.mainwindow.RunMessageBox(_('Layer loaded'),
+ _("%s Layer loaded into Thuban") % layer_count)
+
+def import_mapfile(context):
+ """
+ Import the mapfile from a file given by the user. After that parse
+ the mapfile with the mapscript parser to create all necessary objects.
+
+ Loaded polygon layer like polygon, line or point into thuban.
+ Raster layer are supported also.
+
+ context - the thuban context
+ """
+ # create a new session befor a mapfile is imported
+ if context.mainwindow.save_modified_session() != wx.ID_CANCEL:
+ context.application.SetSession(mainwindow.create_empty_session())
+
+ # context.mainwindow.NewSession()
+ # open a dialog to select the mapfile to import
+ dlg = wx.FileDialog(context.mainwindow,
+ _("Select MapFile file"), ".", "",
+ _("UMN MapServer Mapfiles (*.map)|*.map|") +
+ _("All Files (*.*)|*.*"),
+ wx.OPEN|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ dlg.Destroy()
+ else:
+ return
+
+ # Parse mapfile
+ mapobj = parse_mapfile(filename)
+
+ # shows a dialog to select layers to import
+ selectedlayer = select_layer2import(context,mapobj)
+
+ # counter to show the numer of layer loaded into Tuban
+ layer_count = 0
+ # import settings to thuban only if one layer is selected
+ if len(selectedlayer) != 0:
+ # thuban map context
+ tb_map = context.mainwindow.canvas.Map()
+ # set the titel and projection
+ tb_map.SetTitle(mapobj.get_name())
+ set_projection_to_tb(tb_map,mapobj)
+
+ selectedlayer = list(selectedlayer)
+ # remove not selected layer from the mapfile
+ incount = 0
+ delcount = 0
+ newselect = []
+ for iii in range(0, len(mapobj.get_layers()), 1):
+ if iii in selectedlayer:
+ newselect.append(selectedlayer[incount]-delcount)
+ incount += 1
+ else:
+ mapobj.remove_layer(iii-delcount)
+ delcount += 1
+ selectedlayer = newselect
+
+ # Check for each Layer if it is possible to show in Thuban
+ for layernr in selectedlayer:
+
+ maplayer = mapobj.get_layers()[layernr]
+
+ #check if rasterlayer type
+ if maplayer.get_type() == 'raster':
+ add_rasterlayer(context, tb_map, mapobj, maplayer)
+ layer_count += 1
+
+ #check if polygonlayer type
+ if ((maplayer.get_type() == 'polygon') or
+ (maplayer.get_type() == 'line') or
+ (maplayer.get_type() == 'circle') or
+ (maplayer.get_type() == 'point')):
+ add_polygonlayer(context, tb_map, mapobj, maplayer)
+ layer_count += 1
+
+ if (maplayer.get_type() == 'annotation'):
+ add_annotationlayer(context, tb_map, mapobj, maplayer)
+ layer_count += 1
+
+ # add the map object to thuban, to use it later
+ tb_map.extension_umn_mapobj = mapobj
+
+ # show a message how many layer were loaded into thuban
+ # if the number of layers is not null
+ if layer_count != 0:
+ # get the extent from the map and set it in thuban
+ extentrect = mapobj.get_extent().get_rect()
+ # fit the new map extent to the window
+ context.mainwindow.canvas.FitRectToWindow(extentrect)
+ context.mainwindow.RunMessageBox(_('Layer loaded'),
+ _("%s Layer loaded into Thuban") % layer_count)
+
+def parse_mapfile(filename):
+ """
+ Parse the mapfile.
+
+ Currently this is done using the mapscript module.
+ NOTE: It is also possible to use here an own parser
+ which could at aleast gain independency from the mapscript
+ module.
+
+ filename - the filename of the .map file
+ """
+ theMap = mapObj(filename)
+
+ return MF_Map(theMap)
+
+# check if an mapobj exists, to control the menuitem is available or not
+def _has_umn_mapobj(context):
+ return False
+ """Return true if a umn_mapobj exists"""
+ return hasattr(context.mainwindow.canvas.Map(), "extension_umn_mapobj")
+
+#create a new mapfile
+def create_new_mapfile(context):
+ theMap = MF_Map(mapObj(""))
+ context.mainwindow.canvas.Map().extension_umn_mapobj = theMap
+
+# ###################################
+#
+# Hook in MapServer Extension into Thuban
+#
+# ###################################
+
+# find the extensions menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu("experimental", _("Experimenta&l"))
+# find the extension menu and add a new submenu if found
+mapserver_menu = experimental_menu.FindOrInsertMenu("mapserver", _("&MapServer"))
+
+# register the new command
+registry.Add(Command("create_new_mapfile", _("Create new mapfile"), \
+ create_new_mapfile, \
+ helptext = _("Create a new empty mapscript MapObj")))
+# finally add the new entry to the extensions menu
+mapserver_menu.InsertItem("create_new_mapfile")
+
+# register the new command
+registry.Add(Command("import_mapfile", _("Import mapfile"), import_mapfile,
+ helptext = _("Import a mapfile")))
+# finally add the new entry to the extensions menu
+mapserver_menu.InsertItem("import_mapfile", after = "create_new_mapfile" )
+
+# register the new command
+registry.Add(Command("import_layer_from_mapfile", _("Import layer from mapfile"),
+ import_layer_from_mapfile,
+ helptext = _("Import a layer from a mapfile"),
+ sensitive = _has_umn_mapobj))
+# finally add the new entry to the extensions menu
+mapserver_menu.InsertItem("import_layer_from_mapfile",
+ after = "import_mapfile" )
+
+
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/sample/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/sample/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/sample/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,21 @@
+Howto use the sample with thuban:
+
+iceland.map:
+ start Thuban from the main CVS thuban directory.
+ (the paths to the Iceland datafiles are relative
+ and will work then)
+
+
+Howto view this sample in UMN MapServer (webserver):
+
+ Copy the three files included in this directory to a new directory on
+ your webserver. For example "Iceland". To use the iceland data you
+ must edit the data path in iceland.map, so that it matches to the
+ directory where the data is. At the moment the data path is relative
+ to this directory. The data is in the thuban/Data/iceland directory.
+
+iceland.html:
+ the template for the mapfile.
+
+index.html:
+ the initialisation file for the Iceland Application on web.
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/README
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+This directory contains tests of the umn_mapserver extension.
+
+Howto run test (assume thuban source is under ~/project):
+
+export PYTHONPATH=~/project/thuban:~/project/thuban/Lib:~/project/thuban/test
+python test_mapserver.py
Added: packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/test_mapserver.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/test_mapserver.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/umn_mapserver/test/test_mapserver.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,396 @@
+# -*- coding:latin1 -*-
+
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Jan Schüngel <jschuengel at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Tests for UMN Mapserver extension.
+"""
+
+__version__ = "$Revision: 2307 $"
+# $Source$
+# $Id: test_mapserver.py 2307 2004-07-28 12:46:19Z jschuengel $
+
+# Import the testmodul from python
+import unittest
+
+from mapscript import mapObj
+
+# Import necessary classes from Thuban
+from Thuban.Model.color import Color, Transparent
+
+from Thuban.Model.proj import Projection
+
+# Import the Classes to test
+from Extensions.umn_mapserver.mapfile import MF_Color, \
+ MF_Rectangle, MF_Style, MF_Map, MF_Projection, \
+ MF_Class, MF_Layer, MF_Metadata, MF_Outputformat, \
+ MF_Symbol, MF_SymbolSet, MF_Scalebar, \
+ MF_Label, MF_Legend, MF_Web
+
+from Extensions.umn_mapserver.mapfile import shp_type
+
+from Extensions.umn_mapserver.mf_import import create_rangeexpression
+
+class mapserver_generalClasses(unittest.TestCase):
+
+ def setUp(self):
+ """
+ Running this funktion befor each test
+ """
+ # using the sample map
+ testMapfile = 'test.map'
+ self.testMap = mapObj(testMapfile)
+ self.eq = self.assertEquals
+
+
+ def test_MF_Color(self):
+ """
+ Testing Color Objects from MapServer.
+ """
+ # IMAGECOLOR 255 255 255
+ testcolor = MF_Color(self.testMap.imagecolor)
+ self.eq(testcolor.get_red(), 255)
+ self.eq(testcolor.get_green(), 255)
+ self.eq(testcolor.get_blue(), 255)
+
+ # set Color with Thuban color obj
+ testthubancolor = Color(0.5,1,0)
+ testcolor.set_thubancolor(testthubancolor)
+ self.eq(testcolor.get_red(),127)
+ self.eq(testcolor.get_green(),255)
+ self.eq(testcolor.get_blue(),0)
+
+ # check if Thubancolor is set correct
+ testtbcolor = testcolor.get_thubancolor()
+ self.eq(testtbcolor.red, 0.5)
+ self.eq(testtbcolor.green, 1)
+ self.eq(testtbcolor.blue, 0)
+
+
+ def test_MF_Rectangle(self):
+ """
+ Testing rectangle objects by example like
+ the mapfile parameter extent.
+ """
+ # EXTENT 622877.17 7019306.94 1095667.78 7447709.31
+ testrect = MF_Rectangle(self.testMap.extent)
+ self.eq(testrect.get_minx(), 622877.17)
+ self.eq(testrect.get_miny(), 7019306.94)
+ self.eq(testrect.get_maxx(), 1095667.78)
+ self.eq(testrect.get_maxy(), 7447709.31)
+
+ # Set a new Rectangle and test if is set correctly
+ testrect.set_rect(50,50,200,200)
+ self.eq(testrect.get_rect(), (50,50,200,200))
+ self.eq(testrect.get_minx(), 50)
+ self.eq(testrect.get_miny(), 50)
+ self.eq(testrect.get_maxx(), 200)
+ self.eq(testrect.get_maxy(), 200)
+
+
+ def test_MF_Metadata(self):
+ """
+ Testing the meta data
+ """
+ # set up to keys to test
+ testmetadata = MF_Metadata(self.testMap)
+ self.eq(self.testMap.getMetaData("titel"), "Iceland Test")
+ testmetadata.add_metadata("test", "test eintrag")
+ self.eq(testmetadata.get_metadatabykey("test"),"test eintrag")
+
+ # generate the MetaData from the testMap
+ testMap2 = MF_Map(self.testMap)
+ testmetadata = testMap2.get_metadata()
+ self.eq(testmetadata.get_metadatabykey("titel"),"Iceland Test")
+
+
+class mapserver_Classes(unittest.TestCase):
+
+ def setUp(self):
+ """
+ Running this funktion befor each test
+ """
+ # using the sample map
+ testMapfile = 'test.map'
+ self.testMap = mapObj(testMapfile)
+ self.eq = self.assertEquals
+
+
+ def test_MF_OutputFormat(self):
+ """
+ Testing the outputformat object
+ """
+ testoutputformat = MF_Outputformat(self.testMap.getOutputFormatByName("png"))
+ self.eq(testoutputformat.get_name(),"png")
+
+
+ def test_MF_Symbolset(self):
+ """
+ Testing the symbolset
+ """
+ testsymbolset = MF_SymbolSet(self.testMap.symbolset)
+ self.eq(testsymbolset.get_symbol(1).get_name(), "circle")
+
+
+ def test_MF_Symbol(self):
+ """
+ Testing the symbol object
+ """
+ testsymbol = MF_Symbol(self.testMap.symbolset.getSymbolByName("circle"))
+ self.eq(testsymbol.get_name(), "circle")
+ assert(testsymbol.get_symbolObj(), self.testMap.symbolset.getSymbolByName("circle"))
+
+ testsymbol.set_filled(True)
+ self.eq(testsymbol.get_filled(), True)
+
+ testsymbol.set_type(4)
+ self.eq(testsymbol.get_type(), 4)
+
+
+ def test_MF_Class(self):
+ """
+ Testing the class object.
+ """
+ # only test the number of styles at the moment
+ testclass = MF_Class(self.testMap.getLayer(0).getClass(0))
+ self.eq (len(testclass.get_styles()), self.testMap.getLayer(0).getClass(0).numstyles)
+
+ # check the name
+ self.eq(testclass.get_name(), "testclass")
+ testclass.set_name("checkout")
+ self.eq(testclass.get_name(), "checkout")
+
+ # check the expressionstring
+ testclass = MF_Class(self.testMap.getLayer(2).getClass(0))
+ self.eq(testclass.get_expressionstring(), '"9"')
+ testclass.set_expressionstring("3")
+ self.eq(testclass.get_expressionstring(), '"3"')
+
+
+ def test_MF_Layer(self):
+ """
+ Testing the layer object with some
+ sample data and classes.
+ """
+ testlayer = MF_Layer(self.testMap.getLayer(2))
+ # NAME 'political' only from layer 1
+ self.eq(testlayer.get_name(), 'cultural')
+ testlayer.set_name('checkout')
+ self.eq(testlayer.get_name(), 'checkout')
+ # check number of classes
+ self.eq(len(testlayer.get_classes()), self.testMap.getLayer(2).numclasses)
+ # check classitem
+ self.eq(testlayer.get_classitem(), "CLPOINT_")
+ testlayer.set_classitem("CLCHECK")
+ self.eq(testlayer.get_classitem(), "CLCHECK")
+ # check data
+ self.eq(testlayer.get_data(), "cultural_landmark-point")
+ testlayer.set_data("test.shp")
+ # .shp will be cutted becouse the source is always a .shp,
+ # or maybe a grafik
+ self.eq(testlayer.get_data(), "test")
+ # check projection (used the pojection obj a little bit)
+ self.eq(testlayer.get_projection().get_projection(), "+proj=latlong+ellps=clrk66")
+ # TYPE POLYGON
+ self.eq(testlayer.get_type(), "point")
+ testlayer.set_type("circle")
+ self.eq(testlayer.get_type(), "circle")
+ # Check status
+ # 0 = off, 1 = on, 2 = default
+ self.eq(testlayer.get_status(), True)
+ testlayer.set_status(False)
+ self.eq(testlayer.get_status(), False)
+
+
+ def test_MF_Map(self):
+ """
+ Testing the mapfile object with samples.
+ """
+ testMapp = MF_Map(self.testMap)
+ # NAME 'ISLAND'
+ self.eq(testMapp.get_name(), 'ISLAND')
+ self.eq(len(testMapp.get_layers()), self.testMap.numlayers)
+
+ # test see in test_MF_Projection
+ testproj = Projection(['proj=utm', 'ellps=clrk66', 'zone=26', 'north'])
+ testMapp.set_projection(testproj)
+ self.eq(testMapp.get_projection().get_params(), ['proj=utm', 'ellps=clrk66', 'zone=26', 'north'])
+
+ self.eq(testMapp.get_size(), (600,450))
+ testMapp.set_size(500,600)
+ self.eq(testMapp.get_size(), (500,600))
+
+
+ def test_MF_Scalebar(self):
+ """
+ Test the Scalebarobj from the testfile
+ """
+ testscalebar = MF_Scalebar(self.testMap.scalebar)
+ self.eq(testscalebar.get_position(mode="string"),"ll")
+ self.eq(testscalebar.get_position(), 3)
+ self.eq(testscalebar.get_intervals(), 4)
+ self.eq(testscalebar.get_status(mode="string"), "OFF")
+
+
+ def test_MF_Label(self):
+ """
+ Test a Label object. In this test use the Label from
+ from the Scalebarobj in the testfile
+ """
+ testlabel = MF_Label(self.testMap.scalebar.label)
+ self.eq(testlabel.get_force(), False)
+ self.eq(testlabel.get_buffer(),0)
+ self.eq(testlabel.get_type(), "bitmap")
+
+
+ def test_MF_Legend(self):
+ """
+ test the legend object from the testfile
+ """
+ testlegend = MF_Legend(self.testMap.legend)
+ self.eq(testlegend.get_status(), False)
+ testlegend.set_status(True)
+ self.eq(testlegend.get_status(), True)
+ testlegend.set_position("ul")
+ self.eq(testlegend.get_position(mode="string"), "ul")
+ testlegend.set_keyspacing(4,5)
+ self.eq(testlegend.get_keyspacing(), (4,5))
+ testlegend.set_keysize(6,7)
+ self.eq(testlegend.get_keysize(), (6,7))
+
+
+ def test_MF_Projection(self):
+ """
+ Projection object is tested with parameters
+ and an epsg code.
+ """
+ # proj=utm
+ # ellps=clrk66
+ # zone=26
+ # north
+ testproj = MF_Projection(self.testMap.getProjection())
+ if testproj.get_params():
+ self.eq(testproj.get_params(), ['proj=utm','ellps=WGS84','zone=26','north'])
+
+ #"init=epsg:26915"
+ if testproj.get_epsgcode():
+ self.eq(testproj.get_epsgcode(), '26915')
+
+
+ def test_MF_Style(self):
+ """
+ Tests a style object with all parameters.
+ """
+ teststyle = MF_Style(self.testMap.getLayer(0).getClass(0).getStyle(0))
+ # OUTLINECOLOR 0 0 0
+ self.eq(teststyle.get_outlinecolor().get_red(), 0)
+ # COLOR 100 200 100
+ self.eq(teststyle.get_color().get_red(), 100)
+ self.eq(teststyle.get_color().get_green(), 200)
+ self.eq(teststyle.get_color().get_blue(), 100)
+ # SIZE 2
+ self.eq(teststyle.get_size(), 2)
+
+
+ def test_MF_Web(self):
+ """
+ Tests a web object
+ """
+ testweb = MF_Web(self.testMap.web)
+ self.eq(testweb.get_imagepath(), "/tmpimg/")
+ testweb.set_imagepath("/tmppathset/")
+ self.eq(testweb.get_imagepath(), "/tmppathset/")
+ self.eq(testweb.get_imageurl(),"/tmpurl/")
+ testweb.set_imageurl("/tmpurlset/")
+ self.eq(testweb.get_imageurl(), "/tmpurlset/")
+
+
+class mapserver_mf_import(unittest.TestCase):
+
+ def setUp(self):
+ """
+ Running this funktion befor each test
+ """
+ # using the sample map
+ testMapfile = 'test.map'
+ self.testMap = mapObj(testMapfile)
+ self.eq = self.assertEquals
+
+
+ def test_create_rangeexpression(self):
+ """
+ testing the range expression creation from the code in the mapfile
+ """
+ # the expressions to test
+ # these expresions are like in thuban
+ test1 = "([ATTR] >= 1 AND [ATTR] <= 100)" # [min,max]
+ code,expr = create_rangeexpression(test1[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[1;100]")
+ test2 = "([ATTR] >= 1 AND [ATTR] < 100)" # [min,max[
+ code,expr = create_rangeexpression(test2[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[1;100[")
+ test3 = "([ATTR] > 1 AND [ATTR] <= 100)" # ]min,max]
+ code,expr = create_rangeexpression(test3[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"]1;100]")
+ test4 = "([ATTR] > 1 AND [ATTR] < 100)" # ]min,max[
+ code,expr = create_rangeexpression(test4[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"]1;100[")
+
+ test5 = "([ATTR] <= 100)" # [-oo,max] , ]-oo,max]
+ code,expr = create_rangeexpression(test5[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[-oo;100]")
+ test6 = "([ATTR] < 100)" # [-oo,max[ , ]-oo,max[
+ code,expr = create_rangeexpression(test6[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[-oo;100[")
+ test7 = "([ATTR] >= 1)" # [min,oo] , [min, oo[
+ code,expr = create_rangeexpression(test7[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[1;oo]")
+ test8 = "([ATTR] > 1)" # ]min,oo] , ]min, oo[
+ code,expr = create_rangeexpression(test8[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"]1;oo]")
+
+ # value equal, works but is not really usefull
+ test9= "([ATTR] < 1 AND [ATTR] >= 1)"
+ code,expr = create_rangeexpression(test9[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[1;1[")
+
+ # works but must be changed the order
+ test10= "([ATTR] <= 100 AND [ATTR] >= 1)"
+ code,expr = create_rangeexpression(test10[1:-1])
+ self.eq(code, "ATTR")
+ self.eq(expr,"[1;100]")
+
+ #singleton not implemented yet
+ test11 = "([ATTR] = 1)"
+ code,expr = create_rangeexpression(test11[1:-1])
+ self.eq(code, None)
+ self.eq(expr,"singleton creation not implemented yet")
+
+ # Attributes not equal
+ test12= "([ATTR] < 100 AND [ATTR2] >= 1)"
+ code,expr = create_rangeexpression(test12[1:-1])
+ self.eq(code, None)
+ self.eq(expr,"Attributes not equal")
+ # dont works, is not supported by thuban
+ test13="([ATTR] > 100 AND [ATTR] < 1)"
+ code,expr = create_rangeexpression(test13[1:-1])
+ self.eq(code, None)
+ self.eq(expr,"values are wrong")
+
+
+if __name__ == '__main__':
+ unittest.main()
Added: packages/thuban/branches/upstream/current/Extensions/wms/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,28 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+# first try out whether we can import the required module
+# of the PyOGCLib.
+ok = True
+try:
+ import ogclib.WMSClient
+except:
+ print "Problems with PyOGCLib (not installed?)"
+ ok = False
+
+if ok:
+ import wms
+
+ from Thuban.UI.extensionregistry import ExtensionDesc, ext_registry
+ from Thuban import _
+
+ ext_registry.add(ExtensionDesc(
+ name = 'WMS',
+ version = '0.2.0',
+ authors= [ 'Jan-Oliver Wagner', 'Martin Schulze' ],
+ copyright = '2003, 2004 Intevation GmbH',
+ desc = _("Provide layers via OGC WMS.")))
Added: packages/thuban/branches/upstream/current/Extensions/wms/capabilities.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/capabilities.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/capabilities.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,192 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Maintain WMS Capabilities
+
+Inherits methods from WMSCapabilitiesParser
+
+class WMSCapabilities:
+ __init__ (resource xor filename xor nothing)
+
+ getErrorMsg()
+
+ fetchCapabilities(resource)
+ saveCapabilities(filename)
+ loadCapabilities(filename)
+ printCapabilities()
+
+ getVersion()
+
+Requirements:
+ - PyOGCLib <http://www.sourceforge.net/projects/pyogclib>
+
+Requires the ogclib installed regularily on the system or checked out
+next to the Thuban checkout.
+
+If this module is executed solitarily, it will fetch the capabilities
+of the frida service and store them in the local file
+frida_capabilities.xml for later processing.
+
+"""
+
+__version__ = "$Revision: 2152 $"
+# $Source$
+# $Id: capabilities.py 2152 2004-04-01 15:34:25Z joey $
+
+import os
+
+# ----------------------------------------------------------------------
+# FIXME: Temporary code until PyOGCLib is a standard requirement
+
+from sys import path
+
+# Assume the PyOGCLib to be checked out next to the thuban main directory
+pyogclib = "../../../PyOGCLib"
+if os.path.isdir(pyogclib) and os.path.isdir(pyogclib + "/ogclib"):
+ path.insert(0, pyogclib)
+
+# We use gettext, so we need to import it and hence need to adjust the
+# path again
+if __name__ == "__main__":
+ path.insert(0, "../../")
+
+# ----------------------------------------------------------------------
+
+from Thuban import _
+
+from ogclib.WMSClient import WMSClient
+from parser import WMSCapabilitiesParser
+
+class WMSCapabilities(WMSClient, WMSCapabilitiesParser):
+ """
+ Thuban class to maintain capabilities. This class provides
+ methods to fetch, save and load capabilities as well as methods to
+ retrieve particular information from the fetched or loaded
+ capabilities XML.
+
+ If an error occured during processing an error text is assigned to
+ self.errorMsg. If everything went fine, this variable is set to
+ None. The current value can be retrieved by the getErrorMsg()
+ method.
+ """
+
+ capabilities = None
+ errorMsg = None
+ wmsVersion = None
+
+ def __init__(self, *parm):
+ """
+ Initialises Capabilities with one optional parameter
+
+ param can be either a URL or a filename:
+
+ filename -- load capabilities from file
+ url -- fetch capabilities from network
+ """
+
+ if parm and parm[0]:
+ if os.path.isfile(parm[0]):
+ self.loadCapabilities(parm[0])
+ else:
+ if parm[0].find("http://", 0) == 0:
+ self.fetchCapabilities(parm[0])
+ else:
+ self.errorMsg \
+ = _("Resource '%s' is neither local file nor URL") \
+ % parm[0]
+
+
+ def getErrorMsg(self):
+ return self.errorMsg
+
+
+ def fetchCapabilities(self, resource):
+ """
+ Fetches the WMS capabilities from an Internet resource
+
+ WMS Protocol version 1.1 is tried first, then 1.0. The
+ protocol version used can be queried by the getVersion()
+ method for later use. If both tries fail, errorMsg will be
+ set accordingly, which can be fetched with getErrorMsg().
+ """
+
+ self.wmsVersion = "1.1"
+ self.capabilities = self.getCapabilities(resource, self.wmsVersion)
+ if not self.capabilities:
+ self.wmsVersion = "1.0"
+ self.capabilities = self.getCapabilities(resource, self.wmsVersion)
+ if not self.capabilities:
+ self.wmsVersion = None
+ self.errorMsg \
+ = _("Resource '%s' "
+ "does support neither WMS version 1.1 nor 1.0") \
+ % resource
+
+ if self.capabilities:
+ self.grok(self.capabilities)
+
+
+ def saveCapabilities(self, fname):
+ """Save capabilities to local file"""
+
+ if self.capabilities is None:
+ self.errorMsg = _("No capabilities available")
+ else:
+ try:
+ out = open(fname, "w")
+ out.write(self.capabilities)
+ out.close()
+ except IOError:
+ self.errorMsg = _("Can't open file '%s' for writing") % fname
+
+
+ def loadCapabilities(self, fname):
+ """Load capabilities from a local file"""
+
+ try:
+ input = open(fname, "r")
+ self.capabilities = input.read()
+ input.close()
+ self.grok(self.capabilities)
+ except IOError:
+ self.errorMsg = _("Can't open file '%s' for reading") % fname
+
+
+ def printCapabilities(self):
+ """Prints capabilities to stdout"""
+
+ print self.capabilities
+
+
+ def getVersion(self):
+ """
+ Returns the WMS protocol version
+
+ If no capabilities could be fetched, None is returned.
+ """
+ return self.wmsVersion
+
+
+if __name__ == "__main__":
+ capabilities \
+ = WMSCapabilities("http://frida.intevation.org/cgi-bin/frida_wms?")
+ if capabilities.getErrorMsg() is None:
+ capabilities.saveCapabilities("frida_capabilities.xml")
+ else:
+ print "Error: " + capabilities.getErrorMsg()
Added: packages/thuban/branches/upstream/current/Extensions/wms/domutils.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/domutils.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/domutils.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,75 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Convenience routines for handling of Document Object Model (DOM)
+nodes.
+
+For more information on DOM see <http://www.zytrax.com/tech/dom/guide.html>.
+
+"""
+
+def listChildNodes (node):
+ """
+ Prints a list of all child DOM nodes for the given node. This
+ function is normally only used for inspection of a DOM tree during
+ development.
+ """
+ print "Node %s has %d children" % (node.nodeName, node.childNodes.length)
+ for i in range (node.childNodes.length):
+ print " %d: %s" % (i, node.childNodes[i].nodeName)
+
+
+def listAttributes (node):
+ """
+ Prints a list of all DOM attributes for the given node. This
+ function is normally only used for inspection of a DOM tree during
+ development.
+ """
+ print "Node %s has %d attributes" % (node.nodeName, node.attributes.length)
+ for key in node.attributes.keys():
+ print " %s=%s" % (key, node.attributes.get(key).nodeValue)
+
+
+# Can't use node.getElementsByTagName(name) since it traverses the XML
+# data recursively and we need hierarchy information as well in order
+# to get inheritance of attributes implemented properly.
+#
+def getElementsByName (node, name):
+ """
+ Returns a list of child DOM nodes whose nodeName matches given
+ string.
+ """
+ res = []
+ for i in range (node.childNodes.length):
+ if node.childNodes[i].nodeName == name:
+ res.append(node.childNodes[i])
+ return res
+
+
+def getElementByName (node, name):
+ """
+ Returns the first child DOM node whose nodeName matches given
+ string.
+ """
+ try:
+ return getElementsByName (node, name)[0]
+ except IndexError:
+ return None
+
+
Added: packages/thuban/branches/upstream/current/Extensions/wms/infodialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/infodialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/infodialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,117 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Information dialog to display various information about a WMS layer.
+
+class wmsInfoDialog(ThubanFrame):
+ __init__
+
+ dialog_layout(text)
+
+ calcText(layer)
+
+"""
+
+__version__ = "$Revision: 2555 $"
+# $Source$
+# $Id: infodialog.py 2555 2005-02-06 16:47:34Z joey $
+
+from Thuban import _
+from Thuban.UI.dialogs import ThubanFrame
+
+from wxPython.wx import wxBoxSizer, wxTextCtrl, wxVERTICAL, \
+ wxHORIZONTAL, wxTE_READONLY, wxTE_MULTILINE, wxTE_LINEWRAP, \
+ wxEXPAND, wxALL, wxButton, wxALIGN_CENTER_HORIZONTAL, wxID_OK, \
+ EVT_BUTTON
+
+
+class wmsInfoDialog(ThubanFrame):
+ """
+ Representation for a simple information dialog
+
+ This dialog will display the title of the WMS resource
+ """
+
+ def __init__(self, parent, name, layer, *args, **kw):
+ """
+ Build the information dialog
+ """
+ title = _("WMS Information")
+ ThubanFrame.__init__(self, parent, name, title)
+
+ self.dialog_layout(self.calcText(layer))
+
+
+ def dialog_layout(self, text):
+ """
+ Set up the information dialog
+ """
+
+ vbox = wxBoxSizer(wxVERTICAL)
+
+ textBox = wxTextCtrl(self, -1, text,
+ style=wxTE_READONLY|wxTE_MULTILINE|wxTE_LINEWRAP)
+ w, h = (500, 300)
+ textBox.SetSizeHints(w, h)
+ textBox.SetSize((w, h))
+
+ vbox.Add(textBox, 1, wxEXPAND|wxALL, 10)
+
+ buttons = wxBoxSizer(wxHORIZONTAL)
+ buttons.Add(wxButton(self, wxID_OK, _("Close")), 0, wxALL, 4)
+ vbox.Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
+
+ EVT_BUTTON(self, wxID_OK, self.OnClose)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(vbox)
+ vbox.Fit(self)
+ vbox.SetSizeHints(self)
+
+
+ def calcText(self, layer):
+ """
+ Generate the text to be displayed in the information window
+
+ It will use several nodes returned by the GetCapabilities
+ request, such as the title, the abstract, fees and access
+ constraints, if they are documented.
+ """
+
+ text = ''
+
+ foo = layer.capabilities.getTitle()
+ if foo != "":
+ text += foo.encode('latin1') + "\n\n"
+
+ foo = layer.capabilities.getAbstract()
+ if foo != "":
+ text += foo + "\n\n"
+
+ foo = layer.capabilities.getFees()
+ if foo != "":
+ text += _("Fees:") + "\n\n" + foo + "\n\n"
+
+ foo = layer.capabilities.getAccessConstraints()
+ if foo != "":
+ text += _("Acces Constraints:") + "\n\n" + foo + "\n\n"
+
+ text += "URL: " + layer.url
+
+ return text
Added: packages/thuban/branches/upstream/current/Extensions/wms/layer.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/layer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/layer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,339 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Graphic Layer via OGC WMS.
+
+class WMSLayer:
+ __init__()
+
+ LatLongBoundingBox()
+ BoundingBox()
+
+ getFormat(format)
+ calcFormat(formats)
+
+ getFormats()
+ getLayers()
+ getLayerTitle()
+
+ getWMSFormat()
+ setWMSFormat(format)
+
+ GetMapImg(width, height, bbox)
+
+Requirements:
+ - PyOGCLib <http://www.sourceforge.net/projects/pyogclib>
+
+Requires the ogclib installed regularily on the system or checked out
+next to the Thuban checkout. Or set the PYTHONPATH to the PyOGCLib
+directory before starting Thuban.
+
+"""
+
+__version__ = "$Revision: 2438 $"
+# $Source$
+# $Id: layer.py 2438 2004-12-09 10:34:03Z joey $
+
+
+from Thuban.Model.layer import BaseLayer
+from Thuban.Model.resource import get_system_proj_file, EPSG_PROJ_FILE, \
+ EPSG_DEPRECATED_PROJ_FILE
+from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+
+from capabilities import WMSCapabilities
+
+from ogclib.WMSClient import WMSClient
+
+
+def epsg_code_to_projection(epsg):
+ """Find the projection for the given epsg code.
+
+ epsg -- EPSG code as string
+ """
+ proj_file, warnings = get_system_proj_file(EPSG_PROJ_FILE)
+
+ for proj in proj_file.GetProjections():
+ if proj.EPSGCode() == epsg:
+ return proj
+ proj_file, warnings = get_system_proj_file(EPSG_DEPRECATED_PROJ_FILE)
+ for proj in proj_file.GetProjections():
+ if proj.EPSGCode() == epsg:
+ return proj
+ return None
+
+
+class WMSLayer(BaseLayer):
+ """
+ WMS Layer
+
+ This layer incorporates all methods from the Thuban BaseLayer and
+ adds specific methods for operating with a WMS server.
+ """
+
+ def __init__(self, title, url):
+ """Initializes the WMSLayer.
+
+ title -- Title of this layer.
+ url -- URL of the WMS-Server wich must contain '?'
+
+ If an error occured, self.error_msg is a string describing
+ the problem(s). Else, self.error_msg is None.
+ """
+ BaseLayer.__init__(self, title, visible = True, projection = None)
+ self.url = url
+ self.bbox = None
+ self.latlonbbox = None
+ self.error_msg = None
+ self.wms_layers = []
+ self.capabilities = None
+
+ # Change the cursor to demonstrate that we're busy but working
+ ThubanBeginBusyCursor()
+ self.capabilities = WMSCapabilities(url)
+ ThubanEndBusyCursor()
+
+ # name of the top layer of the remote map
+ foo = self.capabilities.getLayers()
+ if len(foo) == 0:
+ self.error_msg = _('No layers found in remote resource:\n'\
+ '%s') % url
+ return
+ top_layer = foo[0]
+ self.wms_layers = [top_layer]
+
+ # first projection of the top layer
+ foo = self.capabilities.getLayerSRS(top_layer)
+ if len(foo) == 0:
+ self.error_msg = _('No LatLonBoundingBox found for top layer %s')\
+ % top_layer
+ return
+ top_srs = foo[0]
+
+ # BoundingBox of the top layer
+ bbox = self.capabilities.getLayerBBox(top_layer, top_srs)
+ if len(bbox) == 0:
+ self.error_msg = _('No BoundingBox found for layer %s and EPSG:')\
+ % (top_layer, top_srs)
+ return
+ self.bbox = (float(bbox['minx']),
+ float(bbox['miny']),
+ float(bbox['maxx']),
+ float(bbox['maxy']))
+
+ # LatLonBox of the top layer
+ bbox = self.capabilities.getLayerLatLonBBox(top_layer)
+ self.latlonbbox = (float(bbox['minx']),
+ float(bbox['miny']),
+ float(bbox['maxx']),
+ float(bbox['maxy']))
+
+ # get projection
+ p = epsg_code_to_projection(top_srs)
+ self.SetProjection(p)
+
+ if p is None:
+ self.error_msg = _('EPSG projection code %s not found!\n'\
+ 'Setting projection to "None".\n'\
+ 'Please set an appropriate projection yourself.'\
+ % top_srs)
+
+ # pre-determine the used format
+ self.wmsformat, self.format = \
+ self.calcFormat(self.capabilities.getFormats())
+ if self.wmsformat is None:
+ self.error_msg = \
+ _('No supported image format found in remote resource')
+ return
+
+ # get and set the title
+ self.SetTitle(self.capabilities.getTitle().encode('latin1', 'replace'))
+
+
+ def LatLongBoundingBox(self):
+ """
+ Return the layer's bounding box in lat-lon
+ """
+ return self.latlonbbox
+
+
+ def BoundingBox(self):
+ """
+ Return the layer's bounding box in the intrinsic coordinate system
+ """
+ return self.bbox
+
+
+ def getFormat(self, format):
+ """
+ Return the image format for the render engine
+
+ format -- format as returned by the WMS server
+
+ If no mapping was found, None is returned.
+
+ This routine uses a simple heuristic in order to find the
+ broken down image format to be used with the internal render
+ engine.
+
+ An exception rule is implemented in order to not accept
+ image/wbmp or WBMP which refers to WAP bitmap format and is
+ not supported by the included render engine.
+ """
+ fmap = {'png' : "PNG",
+ 'jpeg': "JPEG",
+ 'jpg' : "JPEG",
+ 'tif' : "TIFF",
+ 'gif' : "GIF",
+ 'wbmp': None,
+ 'bmp' : "BMP"}
+
+ for f in fmap.keys():
+ if format.lower().find(f) > -1:
+ return fmap[f]
+ return None
+
+
+ def calcFormat(self, formats):
+ """
+ Calculate the preferred image format
+
+ formats -- list of formates as returned by the WMS server
+
+ The following priority is used:
+ - PNG
+ - JPEG
+ - TIFF
+ - GIF
+ - BMP
+
+ If no matching format was found, None, None will be returned.
+
+ An exception rule is implemented in order to not accept
+ image/wbmp or WBMP which refers to WAP bitmap format and is
+ not supported by the included render engine.
+ """
+ prio = ['png', 'gif', 'jpeg', 'bmp']
+ for p in prio:
+ for f in formats:
+ if f.lower().find(p) > -1:
+ if f.lower().find('wbmp') == -1:
+ return f, self.getFormat(f)
+ return None, None
+
+
+ def getFormats(self):
+ """
+ Return the list of supported image formats by the WMS server
+
+ These formats may be used in the WMS GetMap request. Data is
+ retrieved from the included WMSCapabilities object.
+
+ The called method from WMSCapabilities will default to
+ 'image/jpeg' if no format is recognised in XML Capabilities,
+ assuming that JPEG will always be supported on the server side
+ with this encoding.
+ """
+ return self.capabilities.getFormats()
+
+
+ def getLayers(self):
+ """
+ Return the list of layer names supported by the WMS server
+
+ Data is retrieved from the included WMSCapabilities object.
+
+ Only named layers will be returned, since a layer may have a
+ title but doesn't have to have a name associated to it as
+ well. If no layers were found, an empty list is returned.
+ """
+ return self.capabilities.getLayers()
+
+
+ def getLayerTitle(self, layer):
+ """
+ Return the title of the named layer
+
+ Data is retrieved from the included WMSCapabilities object.
+
+ If no such title or no such layer exists, an empty string is
+ returned.
+ """
+ return self.capabilities.getLayerTitle(layer)
+
+
+ def getWMSFormat(self):
+ """
+ Return the image format that is used for WMS GetMap requests
+ """
+ return self.wmsformat
+
+
+ def setWMSFormat(self, format):
+ """
+ Set the image format that is used for WMS GetMap requests
+
+ format -- format, one of getFormats()
+ """
+ self.wmsformat = format
+ self.format = self.getFormat(format)
+
+
+ def getVisibleLayers(self):
+ """
+ Return the list of names for all visible layers
+
+ """
+ return self.wms_layers
+
+
+ def setVisibleLayers(self, layers):
+ """
+ Set the list of names for all visible layers
+
+ """
+ self.wms_layers = layers
+
+
+ def GetMapImg(self, width, height, bbox):
+ """
+ Retrieve a new map from the WMS server and return it
+
+ width -- width in pixel of the desired image
+ height -- height in pixel of the desired image
+ bbox -- array of min(x,y) max(x,y) in the given SRS
+
+ SRS and used image format will be retrieved from within the
+ layer itself.
+ """
+ bbox_dict = { 'minx': bbox[0], 'miny': bbox[1],
+ 'maxx': bbox[2], 'maxy': bbox[3] }
+
+ # Change the cursor to demonstrate that we're busy but working
+ ThubanBeginBusyCursor()
+
+ wmsclient = WMSClient()
+
+ epsg_id = int(self.GetProjection().EPSGCode())
+
+ wms_response = wmsclient.getMap(self.url, self.wmsformat, width, height,
+ epsg_id, bbox_dict,
+ self.wms_layers, version = self.capabilities.getVersion())
+ ThubanEndBusyCursor()
+ return wms_response, self.format
Added: packages/thuban/branches/upstream/current/Extensions/wms/parser.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/parser.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/parser.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,527 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Inspect WMS Capabilities for later processing.
+
+Information should only be retrieved with the proper get*() methods.
+
+class WMSCapabilitiesParser:
+ __init__()
+
+ grok(string)
+
+ getTitle()
+ getAbstract()
+ getFees()
+ getAccessConstraints()
+ getFormats()
+ getLayers()
+ getSRS()
+
+ getLayerTitle(layer)
+ getLayerSRS(layer)
+ getLayerLatLonBBox(layer)
+ getLayerBBox(layer, srs)
+
+ isQueryable(layer)
+"""
+
+__version__ = "$Revision: 2439 $"
+# $Source$
+# $Id: parser.py 2439 2004-12-09 10:37:44Z joey $
+
+import xml.dom.minidom
+from xml.dom import Node
+
+from domutils import getElementsByName, getElementByName
+
+from Thuban import _
+
+class WMSCapabilitiesParser:
+ """
+ Thuban class to parse capabilities supplied as large string.
+
+ This class provides methods to parse and retrieve particular
+ information from the WMS capabilities XML. Information should
+ only be extracted by the respective get*() methods.
+ """
+
+ layers = None
+ title = None
+ abstract = None
+ fees = None
+ access = None
+ formats = None
+ error = None
+
+
+ def __init__(self):
+ """
+ Initialises an instance in this class.
+ """
+
+ # Note that we must not initialise internal variables of the
+ # class in a mutable way or it will be shared among all
+ # instances. None is immutable, [] is not.
+ self.error = []
+
+
+ def grok(self, data):
+ """
+ Parses the XML response to a WMS GetCapabilities request.
+
+ Internal datastructure of the class will be filled.
+ Information should only be retrieved with the respective
+ get*() methods.
+ """
+ xml_dom = xml.dom.minidom.parseString(data)
+ root = xml_dom.documentElement
+
+ # Extract the title
+ foo = getElementByName(getElementByName(root, 'Service'), 'Title')
+ if foo:
+ self.title = foo.childNodes[0].data
+
+ # Extract the abstract
+ foo = getElementByName(getElementByName(root, 'Service'), 'Abstract')
+ if foo and len(foo.childNodes[0].data):
+ self.abstract = foo.childNodes[0].data
+
+ # Extract fees information
+ foo = getElementByName(getElementByName(root, 'Service'), 'Fees')
+ if foo and len(foo.childNodes[0].data) \
+ and foo.childNodes[0].data.lower() != 'none':
+ self.fees = foo.childNodes[0].data
+
+ # Extract access information
+ foo = getElementByName(getElementByName(root, 'Service'),
+ 'AccessConstraints')
+ if foo and len(foo.childNodes[0].data) \
+ and foo.childNodes[0].data.lower() != 'none':
+ self.access = foo.childNodes[0].data
+
+ foo = getElementByName(getElementByName(
+ root, 'Capability'), 'Request')
+
+ # Need to distinguish between Map and GetMap for v1.0 and v1.1
+ bar = getElementByName(foo, 'GetMap')
+ if bar:
+ # WMS 1.1
+ foo = getElementsByName(bar, 'Format')
+ self.formats = map((lambda i: i.childNodes[0].data), foo)
+ else:
+ # WMS 1.0
+ foo = getElementByName(getElementByName(
+ foo, 'Map'), 'Format')
+ for node in foo.childNodes:
+ if node.nodeType == Node.ELEMENT_NODE:
+ try:
+ self.formats.append(node.nodeName)
+ except AttributeError:
+ self.formats = [node.nodeName]
+
+ # Extract layer names
+ self.layers = []
+ self.peekLayers(getElementByName(getElementByName(
+ root, 'Capability'), 'Layer'), -1)
+
+ xml_dom.unlink()
+
+
+ def peekLayers(self, top, parent):
+ """
+ Inspect the provided DOM fragment referenced as top.
+
+ This method will inspect all included layers and traverse the
+ tree recursively in order to fill the internal datastructure.
+
+ Note that SRS other than EPSG:* are not yet supported,
+ especially there is no support for AUTO and NONE.
+ """
+
+ index = len (self.layers)
+ self.layers.append({})
+ self.layers[index]['parent'] = parent
+
+ for foo in top.attributes.keys():
+ if foo == 'queryable':
+ self.layers[index]['queryable'] \
+ = int(top.attributes.get(foo).nodeValue)
+
+ foo = getElementByName(top, 'Title')
+ if foo and len(foo.childNodes[0].data):
+ self.layers[index]['title'] = foo.childNodes[0].data
+ else:
+ # A <Title> is required for each layer, <name> is optional
+ # See OGC 01-068r3, 7.1.4.5.1 and 7.1.4.5.2
+ self.error.append(_("No title found for layer #%d") % index)
+
+ foo = getElementByName(top, 'Name')
+ if foo and len(foo.childNodes[0].data):
+ self.layers[index]['name'] = foo.childNodes[0].data
+
+ # These values are only used for an integrity check
+ for foo in getElementsByName(top, 'SRS'):
+ for srs in foo.childNodes[0].data.split(" "):
+ if srs[0:5] == 'EPSG:':
+ srs = srs[5:]
+ try:
+ int(srs)
+ try:
+ self.layers[index]['srs'].append(srs)
+ except KeyError:
+ self.layers[index]['srs'] = [srs]
+ except ValueError:
+ if srs[0:4].upper() == 'AUTO' \
+ or srs[0:4].upper() == 'NONE':
+ try:
+ self.layers[index]['_srs_'].append(srs)
+ except KeyError:
+ self.layers[index]['_srs_'] = [srs]
+ else:
+ self.error.append(_("SRS '%s' is not numerical and not"
+ " AUTO/NONE in layer '%s'") \
+ % (srs, self.layers[index]['title']))
+
+ foo = getElementByName(top, 'LatLonBoundingBox')
+ if foo is not None:
+ self.layers[index]['llbbox'] = {}
+ for corner in ['minx', 'miny', 'maxx', 'maxy']:
+ self.layers[index]['llbbox'][corner] \
+ = foo.attributes.get(corner).nodeValue
+
+ boxes = getElementsByName(top, 'BoundingBox')
+ if boxes != []:
+ self.layers[index]['bbox'] = {}
+ for foo in boxes:
+ srs = foo.attributes.get('SRS').nodeValue
+ if srs[0:5] == 'EPSG:':
+ srs = srs[5:]
+ self.layers[index]['bbox'][srs] = {}
+ for corner in ['minx', 'miny', 'maxx', 'maxy']:
+ self.layers[index]['bbox'][srs][corner] \
+ = foo.attributes.get(corner).nodeValue
+
+ # Traverse subsidiary layers
+ sublayer = getElementsByName(top, 'Layer')
+ for l in sublayer:
+ self.peekLayers(l, index)
+
+
+ def getTitle(self):
+ """
+ Returns the main title of the WMS object.
+
+ If no title is provided in the capabilities, an empty string
+ is returned.
+ """
+ if self.title is None:
+ return ''
+ else:
+ return self.title
+
+
+ def getAbstract(self):
+ """
+ Returns the abstract of the WMS object.
+
+ If no abstract is provided in the capabilities, an empty
+ string is returned.
+ """
+ if self.abstract is None:
+ return ''
+ else:
+ return self.abstract
+
+
+ def getFees(self):
+ """
+ Returns the fees information of the WMS object.
+
+ If no information is provided in the capabilities or if it is
+ set to 'none', an empty string is returned.
+ """
+ if self.fees is None:
+ return ''
+ else:
+ return self.fees
+
+
+ def getAccessConstraints(self):
+ """
+ Returns information about access constraints for the WMS object.
+
+ If no information is provided in the capabilities or if it is
+ set to 'none', an empty string is returned.
+ """
+ if self.access is None:
+ return ''
+ else:
+ return self.access
+
+
+ def getFormats(self):
+ """
+ Returns a list of supported output formats.
+
+ These are used in the GetMap request. This method will
+ default to 'image/jpeg' if no format is recognised in XML
+ Capabilities, assuming that JPEG will always be supported on
+ the server side.
+ """
+ if self.formats is None:
+ return ['image/jpeg']
+ else:
+ return self.formats
+
+ def getLayers(self):
+ """
+ Returns a list of layer names.
+
+ Only named layers will be returned, since a layer may have a
+ title but doesn't have to have a name associated to it as
+ well. If no layers were found, an empty list is returned.
+ """
+ result = []
+ for layer in self.layers:
+ if 'name' in layer:
+ result.append(layer['name'])
+
+ return result
+
+
+ def getSRS(self):
+ """
+ Returns the root list of spatial reference systems (SRS).
+
+ This list is taken from the root layer. Those SRS are common
+ to all subsidiary layers. If no SRS are common to all layers,
+ an empty list is returned. If no layers were detected, an
+ empty list is returned as well.
+ """
+ if len(self.layers) == 0:
+ return []
+
+ # index 0 denotes the root layer by design
+ if 'srs' in self.layers[0].keys():
+ return self.layers[0]['srs']
+
+
+ def getLayerTitle(self, name):
+ """
+ Returns the title of the named layer.
+
+ If no such title or no such layer exists, an empty string is
+ returned.
+ """
+ for layer in self.layers:
+ if 'name' in layer:
+ if layer['name'] == name:
+ if 'title' in layer:
+ return layer['title']
+
+ return ''
+
+
+ def getLayerSRS(self, name):
+ """
+ Returns a list of spacial reference systems (SRS).
+
+ The SRS are specified by the European Petroleum Survey Group
+ (EPSG). There should be at least one SRS per layer, though.
+ The prefix 'EPSG:' will be stripped. If none exists, an empty
+ list is returned.
+
+ The specification [OGC 01-068r3] says about inheritance of
+ SRS:
+
+ - Every layer is available in one or more SRS (or in an
+ undefined SRS)
+
+ - Geographic information whose SRS is undefined
+ (e.g. digitised historical maps) shall use 'NONE'
+ (case-sensitive). This implementation does not support
+ this.
+
+ - Every layer shall have at least one SRS element that is
+ either stated explicitly or inherited from a parent layer.
+
+ - The root layer element shall include a sequence of zero or
+ more SRS elements listing all SRS which are common for to
+ all subsidiary layers.
+
+ - Layers may optionally add to the global SRS list, or to the
+ list inherited from a parent layer.
+
+ - A server which has the ability to transform data to
+ different SRSes may choose not to provide an explicit
+ BoundingBox for every possible SRS available for each Layer.
+ Thus the list of <SRS> elements are authoritative.
+
+ This implementation returns the list of SRS for the given
+ layer, calculated by looking at BoundingBoxes defined in the
+ named layer and all layers higher in the hierarchy up to the
+ root layer which weren't overwritten.
+ """
+ for i in range(len(self.layers)):
+ if 'name' in self.layers[i]:
+ if self.layers[i]['name'] == name:
+ pivot = i
+ break
+ else:
+ return []
+
+ result = []
+ while pivot != -1:
+ if 'srs' in self.layers[pivot]:
+ for srs in self.layers[pivot]['srs']:
+ if srs not in result:
+ result.append(srs)
+ pivot = self.layers[pivot]['parent']
+
+ return result
+
+
+ def getLayerLatLonBBox(self, name):
+ """
+ Returns a dictionary of the LatLonBoundingBox.
+
+ ... for the named layer if it exists. The SRS is always
+ EPSG:4326 per convention. There should be at least one,
+ though, inherited from the root layer at least. If none
+ exists, the value None is returned.
+ """
+ for layer in self.layers:
+ if 'name' in layer:
+ if layer['name'] == name:
+ if 'llbbox' in layer:
+ return layer['llbbox']
+ else:
+ # No LatLonBoundingBox found in current layer,
+ # so traverse the hierarchy upwards and check
+ # again until there is one.
+ pivot = layer
+ while pivot['parent'] != -1:
+ pivot = self.layers[pivot['parent']]
+ if 'llbbox' in pivot:
+ return pivot['llbbox']
+
+ return None
+
+
+ def getLayerBBox(self, name, srs):
+ """
+ Returns a dictionary of the BoundingBox.
+
+ If no such BoundingBox exists, None is returned.
+
+ The specification [OGC 01-068r3] says about BoundingBoxes:
+
+ - Layers may have zero or more BoundingBox elements what are
+ either stated explicitly or inherited from a parent layer.
+
+ - A layer may have multiple BoundingBox elements, but each one
+ shall state a different SRS.
+
+ - A layer inherits any BoundingBoxes defined by its
+ parents.
+
+ - A BoundingBox inherited from the parent layer for a
+ particular SRS is replaced by any declaration for the same
+ SRS in the current layer.
+
+ - A BoundingBox in the child layer for a new SRS which is not
+ already declared by the parent, is added to the list of
+ BoundingBoxes for the child layer.
+
+ - A single layer shall not contain more than one BoundingBox
+ element for the same SRS.
+ """
+ for layer in self.layers:
+ if 'name' in layer:
+ if layer['name'] == name:
+ if 'bbox' in layer:
+ if srs in layer['bbox']:
+ return layer['bbox'][srs]
+
+ # No BoundingBox for the given SRS found in
+ # current layer, so traverse the hierarchy upwards
+ # and check again until there is one.
+ pivot = layer
+ while pivot['parent'] != -1:
+ pivot = self.layers[pivot['parent']]
+ if 'bbox' in pivot:
+ if srs in pivot['bbox']:
+ return pivot['bbox'][srs]
+
+ # No matching BBox found, let's see if it was EPSG:4326
+ if srs == '4326':
+ return self.getLayerLatLonBBox(name)
+
+ return None
+
+
+ def isQueryable(self, name):
+ """
+ Returns the value of the queryable attribute of a layer.
+
+ This attribute denotes whether this layer can be queried
+ through the GetFeatureInfo request. The default value is 0.
+
+ The specification [OGC 01-068r3] this attribute can be
+ inherited.
+ """
+
+ for layer in self.layers:
+ if 'name' in layer:
+ if layer['name'] == name:
+ try:
+ return layer['queryable']
+ except KeyError:
+ # No attribute in this layer, so traverse the
+ # hierarchy upwards
+ pivot = layer
+ while pivot['parent'] != -1:
+ pivot = self.layers[pivot['parent']]
+ if 'queryable' in pivot:
+ return pivot['queryable']
+ return 0
+
+
+
+if __name__ == "__main__":
+ print "This module cannot be executed standalone."
+
+ import os
+
+ sample = "test/sample.xml"
+ try:
+ f = open(sample, "r")
+ except IOError:
+ try:
+ f = open(os.path.dirname(__file__) + "/" + sample, "r")
+ except IOError:
+ print "Cannot open %s for reading" % sample
+
+ if f is not None:
+ sample = f.read();
+ f.close()
+
+ ina = WMSCapabilitiesParser()
+ ina.grok(sample)
Added: packages/thuban/branches/upstream/current/Extensions/wms/properties.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/properties.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/properties.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,192 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Edit Layer Properties
+
+class wmsProperties(NonModalNonParentDialog):
+ __init__
+
+ dialog_layout(text)
+
+ OnOK(event)
+ OnCancel(event)
+
+Problems:
+
+ 1. The wxTextCtrl should fit to the right side of the horizontal
+ box/sizer. It doesn't. I only found the sizer.Add() method to
+ be able to take proportions but no way to tell the object to
+ fill all remaining space.
+
+ 2. The framed box "Layers" needs to be scrollable if there are
+ more than 12 items, since the dialog would probably not fit on
+ people's screen anymore.
+
+ Todo: This can be solved (in C it was possible at least),
+ probably with wxScrolledWindow
+
+ 3. The button hbox is not aligned to the right side which should
+ be. For some reason wxALIGN_RIGHT does not have any effect.
+ Maybe I just misunderstood the documentation?
+
+"""
+
+__version__ = "$Revision: 2440 $"
+# $Source$
+# $Id: properties.py 2440 2004-12-09 10:39:43Z joey $
+
+from Thuban import _
+from Thuban.UI.dialogs import NonModalNonParentDialog
+
+from wxPython.wx import *
+# wxBoxSizer, wxVERTICAL, wxHORIZONTAL, \
+# wxButton, wxID_OK, wxID_CANCEL, wxALL, wxALIGN_CENTER_HORIZONTAL, \
+# EVT_BUTTON, wxEXPAND, wxStaticBoxSizer, wxStaticBox, wxALIGN_RIGHT, \
+# wxALIGN_BOTTOM
+
+ID_WMS_TITLE = 5001
+ID_WMS_LAYER = 5002
+ID_WMS_FORMATS = 5003
+
+MAX_LAYERNAME_LENGTH = 45
+MAX_VISIBLE_LAYERS = 12
+
+class wmsProperties(NonModalNonParentDialog):
+ """
+ Representation for the WMS properties dialog
+ """
+
+ def __init__(self, parent, name, layer, *args, **kw):
+ """
+ Build the properties dialog
+ """
+ title = _("Edit WMS Properties")
+ NonModalNonParentDialog.__init__(self, parent, name, title)
+
+ self.layer = layer
+
+ # Hooks for the widgets to get user data
+ self.entry = None
+ self.layers = {}
+ self.formats = None
+
+ self.dialog_layout(layer)
+
+
+ def dialog_layout(self, layer):
+ """
+ Set up the information dialog
+ """
+
+ # main box for the entire dialog
+ mainbox = wxBoxSizer(wxHORIZONTAL)
+
+ # vertical box to contain the three parts
+ # (title, layers, formats+buttons)
+ vbox = wxBoxSizer(wxVERTICAL)
+ mainbox.Add(vbox, 0, wxALL|wxEXPAND, 4)
+
+ # edit the title
+ hbox = wxBoxSizer(wxHORIZONTAL)
+ vbox.Add(hbox, 0, wxALL, 0)
+ label = wxStaticText(self, ID_WMS_TITLE, _("Title:"))
+ hbox.Add(label, 1, wxALL|wxEXPAND, 4)
+ self.entry = wxTextCtrl(self, ID_WMS_TITLE, layer.Title())
+ hbox.Add(self.entry, 7, wxALL|wxEXPAND|wxALIGN_RIGHT, 0)
+
+ layerbox = wxStaticBox(self, ID_WMS_LAYER, _("Layers"))
+ lbox = wxStaticBoxSizer(layerbox, wxVERTICAL)
+ vbox.Add(lbox, 0, wxALL, 0)
+ visible = layer.getVisibleLayers()
+ for l in layer.getLayers():
+ checker = wxCheckBox(self, ID_WMS_LAYER, layer.getLayerTitle(l)[0:MAX_LAYERNAME_LENGTH].encode('latin1'))
+ self.layers[l] = checker
+ if l in visible:
+ checker.SetValue(True)
+ lbox.Add(checker, 0, wxALL|wxEXPAND, 0)
+
+ # tiled box:
+ hbox = wxBoxSizer(wxHORIZONTAL)
+ vbox.Add(hbox, 0, wxALL|wxEXPAND, 0)
+
+ # left part: image format selection
+ formatbox = wxBoxSizer(wxHORIZONTAL)
+ hbox.Add(formatbox, 1, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 0)
+ label = wxStaticText(self, ID_WMS_FORMATS, _("Format:"))
+ formatbox.Add(label, 0, wxALL|wxALIGN_CENTER_VERTICAL, 4)
+ self.formats = wxChoice(self, ID_WMS_FORMATS)
+ formatbox.Add(self.formats, 1, wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL, 4)
+
+ # fill the select box
+ match = 0
+ count = 0
+ format = layer.getWMSFormat()
+ for f in layer.getFormats():
+ self.formats.Append(f)
+ if f == format:
+ match = count
+ count += 1
+
+ self.formats.Fit()
+ self.formats.SetSelection(match)
+
+ # Build the button hbox, to be added into row
+ buttons = wxBoxSizer(wxHORIZONTAL)
+ hbox.Add(buttons, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 0)
+ buttons.Add(wxButton(self, wxID_OK, _("OK")), 0, wxALL, 4)
+ buttons.Add(wxButton(self, wxID_CANCEL, _("Cancel")), 0, wxALL, 4)
+ EVT_BUTTON(self, wxID_OK, self.OnOK)
+ EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(mainbox)
+ mainbox.Fit(self)
+ mainbox.SetSizeHints(self)
+
+
+ def OnOK(self, event):
+ """
+ Handle the 'OK button pressed' event
+
+ i.e. transfer user input into the layer
+ """
+
+ # Set the title
+ self.layer.SetTitle(self.entry.GetValue())
+
+ # Set the image format for WMS GetMap requests
+ selection = self.formats.GetSelection()
+ if selection > -1:
+ self.layer.setWMSFormat(self.formats.GetString(self.formats.GetSelection()))
+
+ # Set the list of visible layers
+ visible = []
+ for l in self.layers.keys():
+ if self.layers[l].IsChecked():
+ visible.append(l)
+ self.layer.setVisibleLayers(visible)
+
+ self.Close()
+
+
+ def OnCancel(self, event):
+ """
+ Handle the 'Cancel button pressed' event
+ """
+ self.Close()
Added: packages/thuban/branches/upstream/current/Extensions/wms/test/adjustpath.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/test/adjustpath.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/test/adjustpath.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,40 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Add the main Thuban directory to the path, so that Thuban modules can
+be added without problems.
+
+Exported variables:
+
+thubandir -- absolute path to the main Thuban directory
+
+"""
+
+__version__ = "$Revision: 2117 $"
+# $Source$
+# $Id: adjustpath.py 2117 2004-03-19 17:00:17Z joey $
+
+import os
+from sys import path
+
+if os.path.dirname(__file__) == "" or os.path.dirname(__file__) == ".":
+ thubandir = os.path.abspath("../../..")
+else:
+ thubandir = os.path.abspath(os.path.dirname(__file__) + "/../../..")
+path.insert(0, thubandir)
Added: packages/thuban/branches/upstream/current/Extensions/wms/test/test_domutils.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/test/test_domutils.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/test/test_domutils.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,171 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Test for the domutils module
+
+"""
+
+__version__ = "$Revision: 2122 $"
+# $Source$
+# $Id: test_domutils.py 2122 2004-03-24 11:47:31Z joey $
+
+import unittest
+import xml.dom.minidom
+
+import adjustpath
+
+from Extensions.wms.domutils import getElementByName, getElementsByName
+
+
+class TestDOMutils(unittest.TestCase):
+ """
+ Defines a test environment for the class WMSCapabilities.
+ """
+
+ root = None
+
+ def setUp(self):
+ """
+ Set up the XML test string, parse it into a DOM element and
+ hook it to the internal root variable.
+ """
+ data = "\n".join(['<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>',
+ '<!DOCTYPE WMT_MS_Capabilities SYSTEM "http://www.digitalearth.gov/wmt/xml/capabilities_1_0_8.dtd">',
+ '<WMT_MS_Capabilities version="1.0.8" updateSequence="0">',
+ ' <Layer>',
+ ' <Name>Osnabrueck</Name>',
+ ' <Layer>',
+ ' <Name>gewaesser</Name>',
+ ' <Layer queryable="0" opaque="0" cascaded="0">',
+ ' <Name>gewaesserpolyl</Name>',
+ ' </Layer>',
+ ' </Layer>',
+ ' <Layer queryable="0" opaque="0" cascaded="0">',
+ ' <Name>gruenflaechen</Name>',
+ ' </Layer>',
+ ' </Layer>',
+ '</WMT_MS_Capabilities>'])
+ self.root = xml.dom.minidom.parseString(data).documentElement
+
+
+ def compareLists(self, foo, bar):
+ """
+ Compare two lists
+ - check same number of elements
+ - check whether all elements in the first list are part of the second
+ """
+
+ # Check for same number of elements
+ if len(foo) != len(bar):
+ self.fail("Different number of elements");
+
+ # Loop through all elements for existance
+ for elm in foo:
+ if elm not in bar:
+ self.fail("%s not in second list" % elm);
+
+
+ def compareNodeLists (self, result, nodelist):
+ """
+ Compares the Name children versus the given result list.
+ """
+
+ names = []
+ for pivot in nodelist:
+ for i in range (pivot.childNodes.length):
+ if pivot.childNodes[i].nodeName == 'Name':
+ names.append(pivot.childNodes[i].childNodes[0].data)
+
+ self.compareLists(result, names)
+
+
+ def compareNode (self, result, node):
+ """
+ Compares the Name child versus the given result.
+ """
+
+ for i in range (node.childNodes.length):
+ if node.childNodes[i].nodeName == 'Name':
+ self.assertEquals(result, node.childNodes[i].childNodes[0].data)
+ break
+ else:
+ self.fail("No Name child found.");
+
+
+ def test_compareLists (self):
+ """
+ Test the internal compareLists function.
+ """
+
+ # Zero element
+ self.compareLists([], [])
+
+ # Single element
+ self.compareLists(['alpha'], ['alpha'])
+
+ # Multiple elements
+ self.compareLists(['alpha', 'beta', 'gamma'], ['alpha', 'beta', 'gamma'])
+
+ # Multiple elements, different order
+ self.compareLists(['alpha', 'beta', 'gamma'], ['gamma', 'alpha', 'beta'])
+
+
+ def test_getElementsByName (self):
+ """
+ Test for the getElementsByName function.
+ """
+
+ # Test for level 1
+ result = ['Osnabrueck']
+ self.compareNodeLists(result, getElementsByName(self.root, 'Layer'))
+
+ # Test for level 2
+ result = ['gruenflaechen', 'gewaesser']
+ self.compareNodeLists(result, getElementsByName(getElementsByName(self.root, 'Layer')[0], 'Layer'))
+
+ # Test for level 3
+ result = ['gewaesserpolyl']
+ self.compareNodeLists(result,
+ getElementsByName
+ (getElementsByName
+ (getElementsByName
+ (self.root, 'Layer')[0], 'Layer')[0], 'Layer'))
+
+
+ def test_getElementByName (self):
+ """
+ Test for the getElementByName function.
+ """
+
+ # Test for level 1
+ self.compareNode('Osnabrueck', getElementByName(self.root, 'Layer'))
+
+ # Test for level 2
+ self.compareNode('gewaesser', getElementByName(getElementByName(self.root, 'Layer'), 'Layer'))
+
+ # Test for level 3
+ self.compareNode('gewaesserpolyl',
+ getElementByName
+ (getElementByName
+ (getElementByName
+ (self.root, 'Layer'), 'Layer'), 'Layer'))
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/Extensions/wms/test/test_ogclib.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/test/test_ogclib.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/test/test_ogclib.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,262 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test for the PyOGCLib from Sean C. Gillies <sgillies at users.sourceforge.net>
+
+http://www.sourceforge.net/projects/pyogclib
+
+Requires the ogclib installed regularily on the system, accessible via
+PYTHONPATH or checked out alongside the Thuban checkout.
+"""
+
+__version__ = "$Revision: 2430 $"
+# $Source$
+# $Id: test_ogclib.py 2430 2004-11-30 16:59:01Z joey $
+
+import os
+import unittest
+
+from string import split
+from sys import path
+
+from adjustpath import thubandir
+path.insert(0, thubandir + "/test")
+
+import support
+
+# ----------------------------------------------------------------------
+# FIXME: Temporary code until PyOGCLib is a standard requirement
+
+from sys import path
+
+# Assume the PyOGCLib to be checked out next to the thuban main directory
+# setting PYTHONPATH accordingly is fine as well
+#
+pyogclib = os.path.abspath(thubandir + "/../PyOGCLib")
+if os.path.isdir(pyogclib) and os.path.isdir(pyogclib + "/ogclib"):
+ path.insert(0, pyogclib)
+# ----------------------------------------------------------------------
+
+_pyogclib_import_error = None
+try:
+ from ogclib.WMSClient import WMSClient
+except ImportError, extra:
+ _pyogclib_import_error = str(extra)
+
+
+class TestOGCLib(unittest.TestCase):
+ """
+ Defines a test environment for the PyOGCLib, i.e. check whether URL
+ strings are built properly.
+ """
+
+ wmsclient = None
+
+ def setUp(self):
+ skip_if_no_ogclib()
+ self.wmsclient = WMSClient()
+
+ def compare_URLs(self, foo, bar):
+ """
+ Check if two URLs are equal, i.e.:
+ - check for same base URL
+ - check same number of HTTP GET arguments
+ - check whether all arguments from one URL also exist in the second
+ """
+
+ foo_tuple = split(foo, "?")
+ bar_tuple = split(bar, "?")
+
+ # Check for same base URL
+ if foo_tuple[0] != bar_tuple[0]:
+ self.fail("%s != %s" %(foo_tuple[0], bar_tuple[0]))
+
+ # Check for same length of entire HTTP GET argument string
+ if len(foo_tuple) != len(bar_tuple):
+ self.fail("One URL has no arguments");
+
+ # Loop through all HTTP GET arguments for existance
+ if len(foo_tuple) > 1 and len(bar_tuple) > 1:
+ foo_opts = split(foo_tuple[1], "&")
+ bar_opts = split(bar_tuple[1], "&")
+
+ if len(foo_opts) != len(bar_opts):
+ self.fail("Different number of arguments");
+
+ for part in foo_opts:
+ if part not in bar_opts:
+ self.fail("%s not in second argument list" % part);
+
+
+ def test_compareURLs(self):
+ """Perform some tests for own compare routine"""
+
+ # Compare same base URL
+ result = "http://frida.intevation.org/cgi-bin"
+ self.compare_URLs("http://frida.intevation.org/cgi-bin", result)
+
+ # Compare different base URL with same length
+ self.assertRaises(AssertionError, self.compare_URLs, "http://frida.intevation.org/cgi-lib", result)
+
+ # Compare same bse with one argument
+ result = "http://frida.intevation.org/cgi-bin?foo=eins"
+ self.compare_URLs("http://frida.intevation.org/cgi-bin?foo=eins", result)
+
+ # Compare same base URL differnt first argument
+ self.assertRaises(AssertionError, self.compare_URLs, "http://frida.intevation.org/cgi-bin?bar=eins", result)
+
+ # Compare same base with two arguments
+ result = "http://frida.intevation.org/cgi-bin?foo=eins&bar=zwei"
+ self.compare_URLs("http://frida.intevation.org/cgi-bin?foo=eins&bar=zwei", result)
+ self.compare_URLs("http://frida.intevation.org/cgi-bin?bar=zwei&foo=eins", result)
+
+ # Compare same base with different two arguments
+ self.assertRaises(AssertionError, self.compare_URLs, "http://frida.intevation.org/cgi-bin?foo=zwei&bar=eins", result)
+
+ # Compare same base with three arguments
+ result = "http://frida.intevation.org/cgi-bin?foo=eins&bar=zwei&baz=jan&quux=tux"
+ self.compare_URLs("http://frida.intevation.org/cgi-bin?foo=eins&bar=zwei&baz=jan&quux=tux", result)
+ self.compare_URLs("http://frida.intevation.org/cgi-bin?baz=jan&bar=zwei&quux=tux&foo=eins", result)
+
+ # Compare same base with different three arguments
+ testurl = "http://frida.intevation.org/cgi-bin?baz=jan&foo=zwei&quux=tux&bar=eins"
+ self.assertRaises(AssertionError, self.compare_URLs, testurl, result)
+
+
+ def test_CapabilityURL(self):
+ """Test the getCapabilitiesURL() method"""
+
+ frida = "http://frida.intevation.org/cgi-bin/frida_wms?"
+
+ url = self.wmsclient.getCapabilitiesURL(frida, "1.0")
+ result = frida + "WMTVER=1.0&REQUEST=capabilities"
+ self.compare_URLs(url, result)
+
+ url = self.wmsclient.getCapabilitiesURL(frida, "1.1")
+ result = frida + "VERSION=1.1&SERVICE=WMS&REQUEST=GetCapabilities"
+ self.compare_URLs(url, result)
+
+
+ def test_GetMapURL(self):
+ """Test the getMapURL() method"""
+
+ frida = "http://frida.intevation.org/cgi-bin/frida_wms?"
+
+ format = 'image/jpeg'
+ format_enc = 'image%2Fjpeg'
+ width = 400
+ height = 350
+ epsg = 4326
+ bbox = {'minx': -107, 'miny': 40, 'maxx': -109, 'maxy': 41}
+ layers = [ ]
+ styles = [ ]
+ version = '1.1'
+
+ result_base = frida + "WMTVER=1.0&REQUEST=map" + \
+ "&FORMAT="+format_enc + \
+ "&SRS=EPSG%s%d" %("%3A", epsg) + \
+ "&BBOX=%f%s%f%s%f%s%f" %(bbox['minx'], "%2C", bbox['miny'], "%2C",
+ bbox['maxx'], "%2C", bbox['maxy']) + \
+ "&WIDTH=%s" % width + "&HEIGHT=%s" % height
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version)
+
+ # Repeat and continue with version 1.1, as denoted in OGC 01-068r3
+ version = '1.1'
+ result_base = frida + "VERSION=1.1&SERVICE=WMS&REQUEST=GetMap" + \
+ "&FORMAT="+format_enc + \
+ "&SRS=EPSG%s%d" %("%3A", epsg) + \
+ "&BBOX=%f%s%f%s%f%s%f" %(bbox['minx'], "%2C", bbox['miny'], "%2C",
+ bbox['maxx'], "%2C", bbox['maxy']) + \
+ "&WIDTH=%s" % width + "&HEIGHT=%s" % height
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version)
+ self.compare_URLs(result, url)
+
+ result += "&TRANSPARENT=TRUE"
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version,
+ transparent=1 )
+ self.compare_URLs(result, url)
+
+ result += "&BGCOLOR=0xFF00FF"
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version,
+ transparent=1, bgcolor='0xFF00FF')
+ self.compare_URLs(result, url)
+
+ layers = [ 'foo' ]
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version)
+ self.compare_URLs(result, url)
+
+ layers.append('bar')
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version)
+ self.compare_URLs(result, url)
+
+ styles = [ 'something' ]
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version,
+ styles = styles)
+ self.compare_URLs(result, url)
+
+ styles.append('else')
+ result = result_base + \
+ "&LAYERS=" + "%2C".join(layers) + \
+ "&STYLES=" + "%2C".join(styles)
+ url = self.wmsclient.getMapURL(frida, format, width, height, epsg,
+ bbox, layers, version=version,
+ styles = styles)
+ self.compare_URLs(result, url)
+
+
+def skip_if_no_ogclib():
+ if _pyogclib_import_error is not None:
+ raise support.SkipTest(_pyogclib_import_error)
+# raise support.SkipTest("No PyOGCLib found, hence no tests available.")
+
+
+if __name__ == "__main__":
+ support.run_tests()
+
+"""
+
+Additional notes:
+ - Parameter names shall not be case sensitive, but parameter
+ values shall be case sensitive. [OGC 01-068r3, 6.4.1, p13]
+
+ This is not supported by the compare URL method, but may need to
+ in the future.
+
+ - Some geospatial inforamtion may be available at multiple times,
+ like a whether map or satalite photo. Capabilities may announce
+ available times. [OGC 01-068r3, 6.5.7, p18]
+
+ This is not yet supported by WMSClient
+
+ - According to the specs a comma in LAYERS and STYLES list doesn't
+ have to be encoded. Maybe this could cause problems with some
+ servers, just to keep in mind.
+
+"""
Added: packages/thuban/branches/upstream/current/Extensions/wms/test/test_parser.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/test/test_parser.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/test/test_parser.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,319 @@
+# -*- encoding: iso-8859-1 -*-
+#
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Test for WMSCapabilitiesParser from ../parser.py
+
+"""
+
+__version__ = "$Revision: 2382 $"
+# $Source$
+# $Id: test_parser.py 2382 2004-10-04 17:03:29Z joey $
+
+import os
+import unittest
+
+import adjustpath
+
+from Extensions.wms.parser import WMSCapabilitiesParser
+
+
+class TestWMSCapabilitiesParser(unittest.TestCase, WMSCapabilitiesParser):
+ """
+ Defines a test environment for the class WMSCapabilities.
+ """
+
+ def compareLists(self, foo, bar):
+ """
+ Compare two lists
+ - check same number of elements
+ - check whether all elements in the first list are part of the second
+ """
+
+ # Check for same number of elements
+ if len(foo) != len(bar):
+ self.fail("Different number of elements");
+
+ # Loop through all elements for existance
+ for elm in foo:
+ if elm not in bar:
+ self.fail("%s not in second list" % elm);
+
+
+ def compareDicts(self, foo, bar):
+ """
+ Compare two dictionaries (hashes)
+ - check same number of keys
+ - check whether all keys from the first list are part of the second
+ """
+
+ # Check for same number of elements
+ if len(foo) != len(bar):
+ self.fail("Different number of keys");
+
+ # Loop through all elements for existance
+ for key in foo.keys():
+ if key not in bar:
+ self.fail("%s not in second dictionary" % key);
+ if foo[key] != bar[key]:
+ self.fail("%s has different value in second dictionary" % key);
+
+
+ def setUp(self):
+ """
+ Load the locally stored frida capabilities.
+ http://frida.intevation.org/cgi-bin/frida_wms?
+ """
+
+ try:
+ try:
+ f = open("sample.xml", "r")
+ except:
+ f = open(os.path.dirname(__file__) + "/sample.xml", "r")
+ except:
+ print "Cannot open sample.xml for reading"
+ else:
+ xml = f.read();
+ f.close()
+ self.grok(xml)
+
+
+ def test_compareLists(self):
+ """
+ Test the internal compareLists method.
+ """
+
+ # Equality of empty lists
+ self.compareLists([], [])
+
+ # Equality of equal lists
+ self.compareLists([1,2], [1,2])
+
+ # Equality of permuted lists
+ self.compareLists([1,2], [2,1])
+
+ # Equality of large permuted lists
+ self.compareLists([1,2,3,4,5,6,7,8], [8,3,1,2,5,7,4,6])
+
+ # Non-Equality of different lists
+ self.assertRaises(AssertionError, self.compareLists, [1,2], [3,2])
+
+ # Non-Equality of different lists
+ self.assertRaises(AssertionError, self.compareLists, [1,2], [3,2,1])
+
+ # Non-Equality of empty and non-empty list
+ self.assertRaises(AssertionError, self.compareLists, [], [3,2,1])
+
+
+ def test_compareDicts(self):
+ """
+ Test the internal compareDicts method.
+ """
+
+ # Equality of empty dictionaries
+ self.compareDicts({}, {})
+
+ # Equality of equal dictionaries
+ # Python may represent the dictionaries differently
+ self.compareDicts({10:20, 11:30}, {10:20, 11:30})
+
+ # Equality of permuted dictionaries
+ # Python may represent the dictionaries similar anyway
+ self.compareDicts({10:20, 11:30}, {11:30, 10:20})
+
+ # Non-equality of different dictionaries
+ self.assertRaises(AssertionError, self.compareDicts, {10:20, 11:30},
+ {10:20, 11:30, 12:40})
+
+ # Non-equality of empty and non-empty dictionaries
+ self.assertRaises(AssertionError, self.compareDicts, {},
+ {10:20, 11:30, 12:40})
+
+
+ def test_general(self):
+ """
+ Test general attributes extracted from Capabilities XML
+ """
+
+ self.assertEquals(self.getTitle().encode('latin-1'),
+ 'Frida - Freie Vektor-Geodaten Osnabrück')
+ self.assertEquals(self.getAbstract(), '')
+ self.assertEquals(self.getFees(), '')
+ self.assertEquals(self.getAccessConstraints(), '')
+ formats = ['image/gif', 'image/png', 'image/jpeg', 'image/wbmp']
+ self.compareLists(self.getFormats(), formats)
+ layers = ['Osnabrueck', 'gruenflaechen', 'gewaesser',
+ 'gewaesserpolyl','gewaesserlinien', 'strassen_all',
+ 'strassenhinten', 'strassen', 'beschriftung',
+ 'hauptbeschriftung', 'sehenswuerdigkeiten']
+ self.compareLists(self.getLayers(), layers)
+ self.compareLists(self.getSRS(), ['31493'])
+
+
+ def test_LayerTitle(self):
+ """
+ Check if layer titles are recognised properly
+ """
+
+ # main layer
+ self.assertEquals(self.getLayerTitle('Osnabrueck').encode('latin-1'),
+ 'Frida - Freie Vektor-Geodaten Osnabrück')
+
+ # first nested layer
+ self.assertEquals(self.getLayerTitle(
+ 'gruenflaechen').encode('latin-1'),
+ 'Grünflächen')
+
+ # first nested layer
+ self.assertEquals(self.getLayerTitle('gewaesser').encode('latin-1'),
+ 'Gewässer')
+
+ # second nested layer
+ self.assertEquals(self.getLayerTitle(
+ 'gewaesserpolyl').encode('latin-1'),
+ 'Gewässerflächen')
+
+
+ def test_LayerSRS(self):
+ """
+ Check if the SRS are returned properly
+ """
+
+ # SRS of main layer
+ self.compareLists(self.getLayerSRS('Osnabrueck'), ['31493'])
+
+ # Single SRS of layer without inheritance
+ self.compareLists(self.getLayerSRS('gruenflaechen'), ['31493'])
+
+ # Multiple SRS of layer without inheritance, but overwriting
+ self.compareLists(self.getLayerSRS('gewaesserpolyl'),
+ ['31493', '31494'])
+
+ # Multiple SRS of layer with inheritance, one new locally
+ self.compareLists(self.getLayerSRS('gewaesserlinien'),
+ ['31493', '31492'])
+
+ # Multiple SRS with inheritance, two new locally
+ self.compareLists(self.getLayerSRS('strassen'),
+ ['31493', '31494', '31495'])
+
+ # Single SRS with inheritance but overwriting
+ self.compareLists(self.getLayerSRS('beschriftung'),
+ ['31493', '31494', '31495'])
+
+ # SRS of a layer with AUTO SRS ignored
+ self.compareLists(self.getLayerSRS('sehenswuerdigkeiten'), ['31493'])
+
+
+ def test_LatLonBoundingBoxes(self):
+ """
+ Check if the LatLonBoundingBoxes are returned properly
+ """
+
+ # main LatLonBoundingBox
+ bbox = {'minx': "7.92881", 'miny': "52.2131",
+ 'maxx': "8.18349", 'maxy': "52.341"}
+ self.compareDicts(self.getLayerLatLonBBox('Osnabrueck'), bbox)
+
+ # inherited LatLonBoundingBox
+ bbox = {'minx': "7.92881", 'miny': "52.2131",
+ 'maxx': "8.18349", 'maxy': "52.341"}
+ self.compareDicts(self.getLayerLatLonBBox('gewaesser'), bbox)
+
+ # third layer non-inherited LatLonBoundingBox
+ bbox = {'minx': "7.93531", 'miny': "52.2328",
+ 'maxx': "8.17739", 'maxy': "52.3353"}
+ self.compareDicts(self.getLayerLatLonBBox('gewaesserpolyl'), bbox)
+
+
+ def test_BoundingBoxes(self):
+ """
+ Check if the BoundingBoxes are returned properly
+ """
+
+ # main BoundingBox
+ bbox = {'minx': "3.427e+06", 'miny': "5.787e+06",
+ 'maxx': "3.4442e+06", 'maxy': "5.801e+06"}
+ self.compareDicts(self.getLayerBBox('Osnabrueck', '31493'), bbox)
+
+ # inherited BoundingBox
+ self.compareDicts(self.getLayerBBox('gewaesser', '31493'), bbox)
+
+ # overwritten BoundingBox
+ bbox = {'minx': "3.427e+06", 'miny': "5.78901e+06",
+ 'maxx': "3.44173e+06", 'maxy': "5.79952e+06"}
+ self.compareDicts(self.getLayerBBox('gewaesserlinien', '31492'), bbox)
+
+ # multiple BoundingBoxes
+ bbox = {'minx': "3.42743e+06", 'miny': "5.78919e+06",
+ 'maxx': "3.44381e+06", 'maxy': "5.80038e+06"}
+ self.compareDicts(self.getLayerBBox('gewaesserpolyl', '31493'), bbox)
+ bbox = {'minx': "3.42742e+06", 'miny': "5.78918e+06",
+ 'maxx': "3.44380e+06", 'maxy': "5.80037e+06"}
+ self.compareDicts(self.getLayerBBox('gewaesserpolyl', '31494'), bbox)
+
+ # Non-existing BoundingBox
+ self.assertEquals(self.getLayerBBox('beschriftung', '31490'), None)
+
+
+ def test_LatLonBoundingBoxes_as_bboxes(self):
+ """
+ Check if the LatLonBoundingBoxes are returned properly
+ """
+
+ # main LatLonBoundingBox
+ bbox = {'minx': "7.92881", 'miny': "52.2131",
+ 'maxx': "8.18349", 'maxy': "52.341"}
+ self.compareDicts(self.getLayerBBox('Osnabrueck', '4326'), bbox)
+
+ # inherited LatLonBoundingBox
+ bbox = {'minx': "7.92881", 'miny': "52.2131",
+ 'maxx': "8.18349", 'maxy': "52.341"}
+ self.compareDicts(self.getLayerBBox('gewaesser', '4326'), bbox)
+
+ # third layer non-inherited LatLonBoundingBox
+ bbox = {'minx': "7.93531", 'miny': "52.2328",
+ 'maxx': "8.17739", 'maxy': "52.3353"}
+ self.compareDicts(self.getLayerBBox('gewaesserpolyl', '4326'), bbox)
+
+
+ def test_queryable(self):
+ """
+ Check if layers are properly classified queryable or not
+ """
+
+ # implicit setting in main layer
+ self.assertEquals(self.isQueryable('Osnabrueck'), 0)
+
+ # explicit setting in second layer
+ self.assertEquals(self.isQueryable('gruenflaechen'), 0)
+
+ # inherited setting in second layer
+ self.assertEquals(self.isQueryable('gewaesser'), 0)
+
+ # explicit setting in second layer
+ self.assertEquals(self.isQueryable('sehenswuerdigkeiten'), 1)
+
+ # explicit setting in third layer
+ self.assertEquals(self.isQueryable('strassen'), 1)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/Extensions/wms/wms.py
===================================================================
--- packages/thuban/branches/upstream/current/Extensions/wms/wms.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Extensions/wms/wms.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,159 @@
+# Copyright (C) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003, 2004)
+# Bernhard Herzog <bh at intevation.de> (2004)
+# Martin Schulze <joey at infodrom.org> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Provide layers via OGC WMS.
+
+This extension is in a very experimental stage!
+It just demonstrates how to add a special
+layer into Thuban via an extension.
+Some things are not wired, so be prepared for Exceptions
+everywhere.
+"""
+
+__version__ = "$Revision: 2603 $"
+# $Source$
+# $Id: wms.py 2603 2005-04-26 15:04:22Z joey $
+
+import os, sys
+import xml.dom.minidom
+import tempfile
+
+from wxPython.wx import *
+
+from Thuban.Model.proj import Projection
+from Thuban.Model.extension import Extension
+from Thuban.UI.command import registry, Command
+from Thuban.UI.mainwindow import main_menu, layer_properties_dialogs
+from Thuban import _
+import Thuban.UI.baserenderer
+
+from layer import WMSLayer
+
+
+class WMSExtension(Extension):
+ def TreeInfo(self):
+ return (_("Extension: %s") % self.title,
+ [ object.TreeInfo() for object in self.objects ])
+
+
+def render_wms_layer(renderer, layer):
+ offx, offy = renderer.offset
+ width, height = renderer.dc.GetSizeTuple()
+
+ scale = renderer.scale
+ xmin = (0 - offx) / scale
+ ymin = (offy - height) / scale
+ xmax = (width - offx) / scale
+ ymax = (offy - 0) / scale
+
+ img, format = layer.GetMapImg(width, height, (xmin, ymin, xmax, ymax))
+
+ data = (width, height, (img, None, None))
+
+ renderer.draw_raster_data(layer, 0,0, data, format)
+
+ return ()
+
+Thuban.UI.baserenderer.add_renderer_extension(WMSLayer, render_wms_layer)
+from properties import wmsProperties
+layer_properties_dialogs.add(WMSLayer, wmsProperties)
+
+
+class SelectWMSServer(wxDialog):
+
+ ID_COMBOVALUE = 4003
+
+ def __init__(self, parent):
+ wxDialog.__init__(self, parent, -1, _("Select WMS Server"),
+ style = wxDEFAULT_DIALOG_STYLE
+ | wxSYSTEM_MENU
+ | wxRESIZE_BORDER)
+
+ self.combo_value = wxComboBox(self, self.ID_COMBOVALUE, size=(500,-1))
+ self.combo_value.Append("")
+ self.combo_value.Append('http://frida.intevation.org/cgi-bin/frida_wms?')
+ #self.combo_value.Append('http://wms.jpl.nasa.gov/wms.cgi?')
+ #self.combo_value.Append('http://eukrante.hq:9089/cgi-bin/wms_shg?')
+ #self.combo_value.Append('http://131.220.106.112:8080/deegree0.7/wms?')
+ #self.combo_value.Append('http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?CONFIG=gita&')
+ self.combo_value.SetSelection(0)
+
+ button_ok = wxButton(self, wxID_OK, _("OK"))
+ button_ok.SetDefault()
+ button_close = wxButton(self, wxID_CANCEL, _("Close"))
+
+ vbox = wxBoxSizer(wxVERTICAL)
+ vbox.Add(self.combo_value, 1, wxEXPAND|wxALL|wxCB_SORT, 10)
+ hbox = wxBoxSizer(wxHORIZONTAL)
+ hbox.Add(button_ok, 0, wxALL, 10)
+ hbox.Add(button_close, 0, wxALL, 10)
+ vbox.Add(hbox, 0, 10)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(vbox)
+ vbox.Fit(self)
+ vbox.SetSizeHints(self)
+ self.Layout()
+
+ EVT_BUTTON(self, wxID_OK, self.OnOK)
+ EVT_BUTTON(self, wxID_CANCEL, self.OnCancel)
+
+ def OnOK(self, event):
+ self.url = self.combo_value.GetValue()
+ self.EndModal(wxID_OK)
+
+ def OnCancel(self, event):
+ self.EndModal(wxID_CANCEL)
+
+def wms_dialog(context):
+ """Request URL from user and add WMS Layer.
+
+ context -- The Thuban context.
+ """
+ dialog = SelectWMSServer(context.mainwindow)
+
+ if dialog.ShowModal() == wxID_OK:
+ url = dialog.url
+ if len(url) == 0:
+ url = None
+ else:
+ url = None
+ dialog.Destroy()
+
+ if url is None:
+ return
+
+ wms_layer = WMSLayer('A WMS Layer', url)
+ if wms_layer.error_msg is not None:
+ context.mainwindow.RunMessageBox(_('WMS'), wms_layer.error_msg)
+
+ map = context.mainwindow.canvas.Map()
+ if map.projection is None:
+ map.SetProjection(wms_layer.projection)
+ has_layers = map.HasLayers()
+ map.AddLayer(wms_layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ context.mainwindow.canvas.FitMapToWindow()
+
+wxInitAllImageHandlers()
+wms_extension = WMSExtension('WMS')
+
+# register the new command
+registry.Add(Command('wms', _('Add WMS layer ...'), wms_dialog,
+ helptext = _('Add a WMS Layer')))
+
+# find the experimental menu (create it anew if not found)
+experimental_menu = main_menu.FindOrInsertMenu('experimental',
+ _('Experimenta&l'))
+
+# finally add the new entry to the experimental menu
+experimental_menu.InsertItem('wms')
Added: packages/thuban/branches/upstream/current/MANIFEST.in
===================================================================
--- packages/thuban/branches/upstream/current/MANIFEST.in 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/MANIFEST.in 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,20 @@
+include README MANIFEST.in COPYING NEWS ChangeLog
+recursive-include libraries README COPYING LICENSE ChangeLog NEWS MANIFEST.in
+recursive-include libraries *.h *.c *.i *.py *.txt
+recursive-include test README *.py
+recursive-include po README Makefile thuban.pot *.po
+include thuban.py
+recursive-include Thuban *.py
+recursive-include Examples README *.py *.xpm
+recursive-include Extensions README *.py *.xpm *.diff *.apr *.txt
+recursive-include devtools *.py
+include Resources/Bitmaps/*.xpm
+recursive-include Resources/Locale/ *.mo
+include Resources/XML/*.dtd
+include Resources/Projections/*.proj
+recursive-include Doc Makefile README *.xmi *.xml *.png *.xcf *.sk *.ps *.txt
+include packaging/debian/changelog packaging/debian/control
+include packaging/debian/copyright packaging/debian/docs
+include packaging/debian/menu packaging/debian/rules
+include packaging/debian/thuban.1 packaging/debian/watch
+include packaging/windows/thubanstart.py
Added: packages/thuban/branches/upstream/current/NEWS
===================================================================
--- packages/thuban/branches/upstream/current/NEWS 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/NEWS 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,281 @@
+Changes up to Thuban 1.2.0 (released 2007-03-13)
+==========================
+
+ - Python <= 2.4 calls C extension modules with the set locale.
+ This means those modules need to be robust against a locale
+ where LC_NUMERIC is set in a way that the decimal_point might
+ be a comma or something else. Problems are diagnosed
+ at least with shapelib, proj and gdal. To cope with it we:
+
+ + Added a new option --setdecimalcommalocale to runtests.py so that
+ all tests can be checked with a comma as decimal_point, if we
+ can find such an LC_NUMERIC. We only try a few in test/localessupport.py.
+
+ + Fixed behaviour with proj by switching to LC_NUMERIC "C" before
+ initialising the projection and afterward switch back.
+
+ + Added a workaround to internal shapelib and pyshapelib.
+ (Bernhard Reiter)
+
+ - Startup improved: We fail right away if the internal encoding could
+ not be determined. In this case, try to set the LANGUAGE variable to
+ one value and use no colon.
+ If we startup you can see the internal encoding in the about dialog now.
+ (Bernhard Reiter)
+
+ - Support for pysqlite2. (Didrik Pinte)
+
+ - Added packagin directory, which already has an example how
+ to load all extensions on windows. (Didrik Pinte)
+
+ - Updated code to support new style wxPython 2.6 imports. So
+ you need at least wyPython 2.6 . (Didrik Pinte)
+
+ - New Classification "Pattern": Classify text attributes by regexp.
+ (Frank Koormann)
+
+ - New or Improved Extensions:
+
+ + Improved svxexport extension 1.0.1 (Bernhard Reiter)
+
+ * Fixed ARC layer writing: No filling is done.
+ You could actually get polylines with filling in between,
+ when the classification for the lines had a fill color.
+ E.g. this happens when you generate a classification from a ramp.
+
+ * Fixed label export.
+
+ + New export_shapefile extension (Jan-Oliver Wagner)
+ Available from the experimental menu.
+
+ - Known Problems with Extension OGR:
+ - Two tests fail (probably because of an ogr/shapelib problem.)
+ https://wald.intevation.org/tracker/index.php?func=detail&aid=91
+ - Is slower than native Shapefile support.
+ - Classification might not work.
+
+
+Changes in Thuban 1.1.0
+=======================
+
+ - Thuban rembers directories in file selection dialogs during a thuban
+ session
+
+ - Add some support for wxPython 2.5 and 2.6. Thuban is still
+ compatible with wxPython 2.4.
+
+ - Change the way thuban deals with non-ascii text. The internal
+ representation is now the user's default encoding. Thuban works a
+ bit better with a unicode build of wxPython but there are still
+ problems. (Bernhard Herzog)
+
+ - Various raster data improvements. Among other things, translucent
+ images are now supported on a sufficiently recent wxWidgets (2.6).
+ Also, only the part of the window actually covered by the image is
+ drawn. (Jonathan Coles)
+
+ - Improved PostGIS support (Bernhard Herzog):
+
+ - support tables with multiple geometry columns. The user can
+ select which one to use
+
+ - support tables with srids
+
+ - tables don't have to have a column named "gid" anymore. The user
+ can select the column to use for ids
+
+ - PostgreSQL views are supported too
+
+ - support LINESTRING geometries
+
+ - support more PostgreSQL versions. 7.4 works now.
+
+ - Added support for sizable points (Jan-Oliver Wagner)
+
+ - When loading a (moved) session where shapefiles cannot be found, ask
+ the user (Frank Koormann)
+
+ - The middle mouse button can be used for panning now (Russell Nelson)
+
+ - Give a warning when the projection selected for a layer is probably
+ wrong (Russell Nelson)
+
+ - Updated shapelib
+
+ - New or improved extensions:
+
+ - A new extension which exports a map as SVG
+ (Markus Rechtien, Bernhard Reiter)
+
+ - Improved WMS extension (Martin Schulze)
+
+ - New Extension to dump bounding boxes of all shapes of the selected
+ layer (Frank Koormann)
+
+ - New extension: umn_mapserver (Jan Schüngel)
+
+ - New extension: OGR (Nina Hüffmeyer)
+
+ - New Extension: mouseposition. Tool to collect mouse click positions
+ (map coordinates) in a dialog. (Frank Koormann)
+
+ - Documentation:
+
+ - Add some documentation of the internals of Thuban.
+ See Doc/technotes/
+
+ - The thuban manual has been partly translated to German
+ (Jan-Oliver Wagner)
+
+ - Updated translations:
+ Russian (Alex Shevlakov)
+
+ - New translations:
+ Brazilian Portuguese (Eduardo Patto Kanegae)xb
+ Hungarian (Norbert Solymosi)
+
+
+Changes in Thuban 1.0.0
+=======================
+
+ - Updated translations:
+
+ Italian by Maurizio Napolitano
+ Spanish and French by Daniel Calvelo Aros
+ Russian by Alex Shevlakov
+
+ - some minor bug fixes
+
+
+Changes in Thuban 1.0rc1
+========================
+
+ - Redering improvements
+
+ Rendering the map in the main window does not freeze Thuban
+ completely anymore. While the rendering occurs the window is updated
+ regularly to show the progress and you can interact with the window
+ and thuban in general even when the rendering is not complete yet
+
+ The map display is also faster in many cases now, especially when
+ doing classifictions.
+
+ The renderes have a mechanism to define how new layer classes defined
+ in extensions can be rendered (see the new wms extension for an
+ example)
+
+ - Added a few extensions in the Extensions sub-directory. Most of them
+ are experimental to varying extents. Note that the binary packages
+ might not contain all of these extensions.
+
+ - gns2shp
+
+ Convert GNS (GEOnet Names Server) files to shapefiles. See
+ Extensions/gns2shp/gns2shp.py for more information
+
+ - wms
+
+ Use thuban as WMS client. See Extensions/wms/wms.py for more
+ information
+
+ - importAPR
+
+ Import a ArcView project file (.apr) and convert it to Thuban.
+
+ - profiling
+
+ For developers: perfomance measurement for the rendering code.
+ See Extensions/profiling/profiling.py for details.
+
+ - drawshape
+
+ This is a *very experimental* and potentially *dangerous* extension
+ to add shapes to a shapefile. Be careful with it as it may lead to
+ data loss. For more information, see Extensions/drawshape/README
+
+ - A new command line option --enable-attribute-editing, which when
+ given turns on editing of attribute values in the identify view. It
+ only works on layers whose attribute data is stored in DBF files.
+ This experimental and may lead to data loss, so be careful when using
+ it.
+
+ - EPSG projections
+
+ Thuban now comes with two .proj files containing EPSG projections
+ (epsg.proj and epsg-deprecated.proj in Resources/Projections/). These
+ projections can be shown in the dialog with the new check boxes under
+ "Show EPSG".
+
+ - Context menu in the legend window
+
+ The legend window now has a context menu for most of the layer
+ commands
+
+ - Localization updates
+
+ The localization is now done with wxWindow's localization support and
+ thus deals automatically with character encoding transformations and
+ the standard dialogs are also translated properly if the wxWindows
+ .mo files are installed
+
+ Updated translations for French and Spanish contributed by Daniel
+ Calvelo. Updated German translation
+
+ - PostGIS improvements
+
+ - Quote table and columns names properly.
+
+ - The dialog deals better with duplicate connections (e.g. trying to
+ create a new connection when there already is a connection for the
+ same database)
+
+ - Files written with the Windows version of Thuban can now be read by
+ the unix version. The other way round was already possible.
+
+ - The shapefile handling code now uses shapelib 1.2.10
+
+ - Thuban should work without problems and warnings with Python 2.3 now.
+
+
+Changes in Thuban 0.9
+=====================
+
+ - An initial version of the Thuban User's Manual. Currently only the
+ XML sources and the images are shipped with the Thuban sources. The
+ binary distributions do not contain the document at this point. An
+ online version is available at
+ http://thuban.intevation.org/documentation.html
+
+ - New Translations: German, Italian and Russian. The Italian and
+ Russion translations are based on 0.8.1 and therefore not quite up to
+ date. German is up to date, though. For 1.0 we intend to have a
+ translation period where all translations can be brought up to date.
+
+ - PostGIS support. This feaure is still a bit experimental at this
+ point and is not very well tested yet. It should work PostgreSQL
+ 7.2.1 and postgis 0.7 as that's what we tested it with. Newer
+ versions probably also work.
+
+ The user as which the connection is established obviously needs
+ select permissions on any table to show and also on the
+ geometry_columns table.
+
+ Known Issues:
+
+ - Only four geometry types are currently supported: POINT,
+ MULTILINESTRING, POLYGON and MULTIPOLYGON.
+
+ - Tables must have a gid column which is assumed to be a non-NULL
+ integer which uniquely identifies the row.
+
+ - It's not optimized so some things may be very slow. For instance
+ the number of queries done could be reduced substantially
+ especially if you use classifications. Having an index on the gid
+ column can speed things up in that case. Note that at least older
+ versions shp2pgsql do not create such an index.
+
+ - Renamed the subdirectory extensions to libraries. The name extensions
+ can now be used for a directory with Thuban extensions.
+
+
+More changes in even more detail are listed in the ChangeLog file.
Added: packages/thuban/branches/upstream/current/PKG-INFO
===================================================================
--- packages/thuban/branches/upstream/current/PKG-INFO 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/PKG-INFO 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,11 @@
+Metadata-Version: 1.0
+Name: Thuban
+Version: 1.2.0
+Summary: Geographic data viewer
+Home-page: http://thuban.intevation.de/
+Author: Intevation GmbH
+Author-email: thuban at intevation.de
+License: GPL
+Description: Thuban is a viewer for geographic data written in Python
+
+Platform: UNKNOWN
Added: packages/thuban/branches/upstream/current/README
===================================================================
--- packages/thuban/branches/upstream/current/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,115 @@
+
+Thuban - a Geographic Data Viewer
+=================================
+
+$Date: 2007-03-13 22:21:51 +0000 (Di, 13 Mär 2007) $
+$Revision: 2736 $
+
+Thuban is an interactive viewer for geographic data.
+Python and the wxWidgets framework ensure great portability.
+Thuban is Free Software and runs on GNU/Linux, Windows
+and several other operating systems.
+
+Homepage: https://thuban.intevation.org
+Development infrastructure: https://wald.intevation.org/projects/thuban/
+
+About the Name
+--------------
+
+Thuban is the name of a star in the constellation Draco (The Dragon).
+About 4000 years ago it was the north star.
+
+
+Requirements
+------------
+
+Thuban requires the following software to be installed:
+
+ Python 2.2.1 http://www.python.org
+ wxWidgets 2.6.3.2 http://www.wxwidgets.org (formerly known as wxWindows)
+ wxPython 2.6.3.2 http://www.wxpython.org
+ proj 4.4.5 http://www.remotesensing.org/proj/
+ SQLite 2.8.3 http://sqlite.org/
+ PySQLite 1.0.1 http://pysqlite.org/
+
+The versions given are the lowest versions that are known to work. for
+proj, sqlite and pysqlite somewhat older versions probably work as well.
+Note that the wxPython version must be the same as the wxWidgets version
+(Some wxPython binary packages already contain the right wxWidgets version)
+
+Optional software:
+
+ GDAL 1.3.2 http://www.remotesensing.org/gdal/
+ for raster image (geo-tiff) support
+
+ psycopg 1.0.x http://initd.org/software/psycopg
+ for postgis connections. Newer version probably also work
+
+ RXP 1.2.x http://www.cogsci.ed.ac.uk/~richard/rxp.html
+ usually comes directly with pyRXP.
+ pyRXP 0.9 http://www.reportlab.org/pyrxp.html
+ only for the automatic tests to validate Thuban's XML files.
+
+
+Installation
+------------
+
+Building Thuban (this compiles the extension modules but leaves them in
+a directory under build/):
+
+ python setup.py build
+
+
+To setup Thuban to run directly from the source directory:
+
+ python setup.py install_local
+
+You can run this without running build first.
+
+
+To install Thuban:
+
+ python setup.py install
+
+
+for general information about the command line options of the setup.py
+script, run
+
+ python setup.py --help
+
+
+If you build from SVN and want to have translated menus, dialogs etc.
+you have to build the message catalogs manually before you run setup.py.
+See po/README for more information.
+
+
+Build Troubleshooting
+---------------------
+
+When building Thuban, you might have problems because of a missing file
+wx/wxPython/wxPython.h. This file is part of wxPython and may be
+packaged in a separate package. Unfortunately, on some systems this
+file is not packaged at all. On those systems you can try a work-around
+built into Thuban, by passing the --use-wx-python-swig-hack to the
+build_ext command. This can be done on the command line for the build
+command like this:
+
+ python setup.py build_ext --use-wx-python-swig-hack build
+
+You can also use it with the install_local command:
+
+ python setup.py build_ext --use-wx-python-swig-hack install_local
+
+Note, that this work-around relies on some wxPython internals and may
+cease to work at some point. We tested it with wxPython 2.6.
+
+
+License
+-------
+
+Thuban is licensed under the terms of the
+GNU General Public License (GPL) version 2 or later.
+
+However, some of the extension modules in the extension subdirectory are
+licensed under other Free Software licenses.
+See the respective README files for details.
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/bottom_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/bottom_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/bottom_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,31 @@
+/* XPM */
+static char * bottom_layer_xpm[] = {
+"24 24 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #949194",
+" ",
+" ",
+" ",
+" ...........",
+" .+++++++++. ",
+" .+++++++++. ",
+" ....+++++++++. ",
+" .++.+++++++++. ",
+" .++........... ",
+" .+++++++++..........",
+" .+++++++++.++++++++. ",
+" ...........++++++++. ",
+" .+++++++++....",
+" .+++++++++.++. ",
+" ...........++. ",
+" .+++++++++....",
+" . .+++++++++.++.@",
+" .. ...........++.@@",
+" ....... .+++++++++.@@ ",
+" .. .+++++++++.@@ ",
+" . ...........@@ ",
+" @@@@@@@@@@@ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/close_12.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/close_12.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/close_12.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,17 @@
+/* XPM */
+static char * close_12_xpm[] = {
+"12 12 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" . . ",
+" . . ",
+" . . ",
+" .. ",
+" .. ",
+" . . ",
+" . . ",
+" . . ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/dock_12.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/dock_12.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/dock_12.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,20 @@
+/* XPM */
+static char * dock_12_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #000000",
+"+ c #949194",
+"@ c #5A5D5A",
+"# c #FFFFFF",
+" ",
+" ",
+" ",
+" ......... ",
+" .....+++@ ",
+" @###@+++@ ",
+" @###@+++@ ",
+" @###@+++@ ",
+" @###@+++@ ",
+" @###@+++@ ",
+" @@@@@@@@@ ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/fullextent.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/fullextent.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/fullextent.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * fullextent_xpm[] = {
+"24 24 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ...... ...... ",
+" .++++++ ++++.+",
+" .+ .+",
+" .+ .+",
+" .+ .... .... .+",
+" .+ ...++ ...+ .+",
+" + ...+ ...+ +",
+" .++. . +.+ ",
+" + . . + + ",
+" + + ",
+" ",
+" ",
+" ",
+" . . ",
+" . . + . . ",
+" ... + ...+ ",
+" . ...+ ...+ . ",
+" .+ .... ....+ .+",
+" .+ ++++ ++++ .+",
+" .+ .+",
+" .+ .+",
+" ...... ......+",
+" ++++++ ++++++"};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/fulllayerextent.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/fulllayerextent.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/fulllayerextent.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,32 @@
+/* XPM */
+static char * fulllayerextent_xpm[] = {
+"24 24 5 1",
+" c None",
+". c #727272",
+"+ c #FFFFFF",
+"@ c #000000",
+"# c #949194",
+" ",
+" ",
+" ... . ",
+" .+++. ..+.. ",
+" .+++++. ..+++++. ",
+" .+@@@@++...+@@@@++. ",
+" .+@@@##++++++@@@#+. ",
+" .+@@@#+++++++@@@#+. ",
+" .+@##@++++++ at +#@#+. ",
+" .++#++ at ++++@+#++#+. ",
+" .+++++#++++#++++. ",
+" .++++++++++++++. ",
+" .++++++++++++. ",
+" ..++++++++++. ",
+" @++++ at +++++. ",
+" @ @ #++++ at ++@+. ",
+" @@@ # .++++@@@#. ",
+" @@@# .+++@@@#. ",
+" @@@@ .+@@@@#. ",
+" #### .+####. ",
+" .++... ",
+" .. ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/fullselextent.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/fullselextent.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/fullselextent.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,33 @@
+/* XPM */
+static char * fullselextent_xpm[] = {
+"24 24 6 1",
+" c None",
+". c #A8A8A8",
+"+ c #000000",
+"@ c #949194",
+"# c #727272",
+"$ c #FFFFFF",
+" ",
+" ",
+" ... . ",
+" + . . .. +. ",
+" + + . .+ + @. ",
+" . +++@ ... +++ @ . ",
+" . +++@ . +++@ . ",
+" .++++@ ## ++++ . ",
+" . @@@@#$# @@@@ . ",
+" . ##$$$### . ",
+" . #$$$$$$$$# . ",
+" #$$$$$$$$$$# . ",
+" #$$$$$$$$$$#... ",
+" ##$$$$$$$# . ",
+" #$$$$## . ",
+" #$## . ",
+" ++++ # ++++ . ",
+" +++@ .. +++@@. ",
+" +++@ .. +++@ . ",
+" + @+@ ..+@@+ . ",
+" + @ @ . @..+ ",
+" @ .. @ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * group_use_xpm[] = {
+"24 24 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" .. ",
+" ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_all.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_all.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_all.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * group_use_all_xpm[] = {
+"24 24 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. .. ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" .. .. ",
+" ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_none.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_none.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_none.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * group_use_none_xpm[] = {
+"24 24 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. .. ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" ... ... ",
+" .. .. ",
+" ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_not.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_not.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/group_use_not.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * group_use_not_xpm[] = {
+"24 24 2 1",
+" c None",
+". c #000000",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .. ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" ... ",
+" .. ",
+" ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/hide_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/hide_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/hide_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+/* XPM */
+static char * hide_layer_xpm[] = {
+"24 23 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ....... ",
+" ... ... ",
+" ... ... ",
+" .. .. ",
+" .. .. ",
+" .. .. ",
+" .. .+ ",
+" .... ..+ ",
+" .... ....++ ",
+" ...... ......++ ",
+" ...............++ ",
+" +...........+++ ",
+" +.......+++ ",
+" +++++++ ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/identify.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/identify.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/identify.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * identify_xpm[] = {
+"24 24 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ",
+" ",
+" ",
+" . ",
+" .+ .... ",
+" .. ...... ",
+" ..+ ..++++.. ",
+" ... .++ ..+ ",
+" ...+ .+ ..+ ",
+" .... + ..+ ",
+" ....+ ..++ ",
+" ..... ..++ ",
+" .....+ ..++ ",
+" ...... ..+ ",
+" ......+ ..+ ",
+" ....... ++ ",
+" ...+...+ ",
+" ..++ ... .. ",
+" .++ +.+ ..+ ",
+" + + ++ ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/label.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/label.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/label.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * label_xpm[] = {
+"24 24 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ",
+" ",
+" . ... ",
+" .+ .++ ",
+" .. .+ ",
+" ..+ .+ ",
+" ... .+ ",
+" ...+ .+ ",
+" .... .+ ",
+" ....+ .+ ",
+" ..... .+ ",
+" .....+ .+ ",
+" ...... .+ ",
+" ......+ .+ ",
+" ....... .+ ",
+" ...+...+ .+ ",
+" ..++ ... .+ ",
+" .++ +.+ ... ",
+" + ++ +++ ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/layer_properties.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/layer_properties.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/layer_properties.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,32 @@
+/* XPM */
+static char * layer_properties_xpm[] = {
+"24 24 5 1",
+" c None",
+". c #000000",
+"+ c #313031",
+"@ c #949194",
+"# c #FFFFFF",
+" ",
+" ........ +++",
+" .@@@@@@@...+++",
+" .@@@@@@@@@@@+++",
+" .@@@@@@@@@@@@+++",
+" .@@.@@@@@@@@@@+++",
+" ......@@.@@.@@@@@@@@+++",
+" .##+.@@.@@.@@.@@@@@@+++",
+" .##.@@.. at .@@.@@@@@..+++",
+" .#.@@.##.@@.@@..... at +++",
+" .#. at .####..@@.####.@ ",
+" .##.#######..#####.@ ",
+" .##++++##+++++++##.@ ",
+" .##+##############.@ ",
+" .##+##############.@ ",
+" .##++++##+++++++##.@ ",
+" .##+##############.@ ",
+" .##+##############.@ ",
+" .##++++##+++++++##.@ ",
+" .#################.@ ",
+" ...................@ ",
+" @@@@@@@@@@@@@@@@@@@ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,22 @@
+/* XPM */
+static char * legend_icon_map_xpm[] = {
+"16 16 3 1",
+" c None",
+". c #FFFFFF",
+"+ c #000000",
+"................",
+"................",
+"................",
+"................",
+"................",
+".....+++++++++++",
+"....+.........+.",
+"...+.........+..",
+"..+.........+...",
+".+.........+....",
+"+++++++++++.....",
+"................",
+"................",
+"................",
+"................",
+"................"};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_map.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_map.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/legend_icon_map.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,61 @@
+/* XPM */
+static char * map_xpm[] = {
+"15 15 43 1",
+" c None",
+". c #739FBE",
+"+ c #E8ECF1",
+"@ c #5A9152",
+"# c #6696B8",
+"$ c #5189B0",
+"% c #3B7BA6",
+"& c #3476A3",
+"* c #588EB3",
+"= c #7AA4C1",
+"- c #97B7CE",
+"; c #A7C1D5",
+"> c #427FA9",
+", c #5F92B5",
+"' c #DBE3EB",
+") c #6C9BBB",
+"! c #856D5F",
+"~ c #47391A",
+"{ c #4984AC",
+"] c #5DAC62",
+"^ c #1C8129",
+"/ c #42904B",
+"( c #B4CADA",
+"_ c #81A8C4",
+": c #4B9953",
+"< c #F5F4F6",
+"[ c #8AAEC8",
+"} c #CEDBE5",
+"| c #5FAC63",
+"1 c #277333",
+"2 c #166F23",
+"3 c #327E3C",
+"4 c #145E21",
+"5 c #2B7736",
+"6 c #105A1E",
+"7 c #C1D2E0",
+"8 c #176124",
+"9 c #1A6527",
+"0 c #35813F",
+"a c #216C2D",
+"b c #2E7A39",
+"c c #54A35A",
+"d c #398643",
+".+@#$%%&&&%%.#%",
+"*=-;*>%%%%%,'#>",
+"$)!~){>>>>>*]){",
+",+^/)*{>>>{#@(,",
+"*!'^-#${{{$*_:<",
+"$#[<^--$$$$*.}^",
+"{.^|][#,***,#12",
+"{-^3:;~.,,,#)_1",
+"$)[<4:+'-)##)=]",
+"*5/6/]^@;7+;=_;",
+"@^8^^^^5^^9^5@'",
+"_08^a4^:^1|^^'(",
+"*[61/]^!-(;.._-",
+"$#[~2b}+[###)=/",
+"{-!cd-;.,*,,)_d"};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/lower_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/lower_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/lower_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,31 @@
+/* XPM */
+static char * lower_layer_xpm[] = {
+"24 24 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #949194",
+" ",
+" ",
+" ",
+" ........... ",
+" .+++++++++. ",
+" .+++++++++. ",
+" ....+++++++++. ",
+" .++.+++++++++. ",
+" .++........... ",
+" .+++++++++......... ",
+" .+++++++++.+++++++. ",
+" ...........+++++++. ",
+" .+++++++++.... ",
+" . .+++++++++.++. ",
+" . ...........++. ",
+" . .+++++++++....@ ",
+" . .+++++++++.++.@ ",
+" . ...........++.@@ ",
+" . .+++++++++.@@ ",
+" ..... .+++++++++.@@ ",
+" ... ...........@@ ",
+" . @@@@@@@@@@@ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/pan.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/pan.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/pan.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * pan_xpm[] = {
+"24 24 3 1",
+" c None",
+". c #000000",
+"+ c #949194",
+" ",
+" ",
+" ",
+" ",
+" . ",
+" ... ",
+" ..... ",
+" .+++ ",
+" .+ ",
+" . .+ . ",
+" .. .+ .. ",
+" ............... ",
+" ..++++.++++..++ ",
+" .+ .+ .++ ",
+" + .+ + ",
+" .+ ",
+" ..... ",
+" ...+ ",
+" .+ ",
+" + ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/raise_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/raise_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/raise_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,31 @@
+/* XPM */
+static char * raise_layer_xpm[] = {
+"24 24 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #949194",
+" ",
+" ",
+" ",
+" ........... ",
+" . .+++++++++. ",
+" ... .+++++++++. ",
+" ..... .+++++++++.... ",
+" . .+++++++++.++. ",
+" . ...........++. ",
+" . .+++++++++... ",
+" . .+++++++++.+. ",
+" . ...........+. ",
+" . ...+++++++++. ",
+" .+.+++++++++. ",
+" .+........... ",
+" .+++++++++.........@ ",
+" .+++++++++.+++++++.@ ",
+" ...........+++++++.@@ ",
+" .+++++++++.@@ ",
+" .+++++++++.@@ ",
+" ...........@@ ",
+" @@@@@@@@@@@ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/show_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/show_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/show_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,30 @@
+/* XPM */
+static char * show_layer_xpm[] = {
+"24 23 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #949194",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ....... ",
+" ........... ",
+" ............... ",
+" ................. ",
+" ....++....+..++.... ",
+" ....++.........+++... ",
+" ..++++.........+++++.@ ",
+" ..++++.........++++..@ ",
+" ...+++.......++++..@@ ",
+" ...++.......++...@@ ",
+" ....+.....+....@@ ",
+" @...........@@@ ",
+" @.......@@@ ",
+" @@@@@@@ ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/top_layer.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/top_layer.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/top_layer.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,31 @@
+/* XPM */
+static char * top_layer_xpm[] = {
+"24 24 4 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"@ c #949194",
+" ",
+" ",
+" ",
+" . ........... ",
+" .. .+++++++++. ",
+" ....... .+++++++++. ",
+" .. .+++++++++.... ",
+" . .+++++++++.++. ",
+" ...........++. ",
+" .+++++++++... ",
+" .+++++++++.+. ",
+" ...........+. ",
+" ...+++++++++. ",
+" .+.+++++++++. ",
+" .+........... ",
+" .+++++++++.........@ ",
+" .+++++++++.+++++++.@ ",
+" ...........+++++++.@@ ",
+" .+++++++++.@@ ",
+" .+++++++++.@@ ",
+" ...........@@ ",
+" @@@@@@@@@@@ ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/undock_12.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/undock_12.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/undock_12.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,20 @@
+/* XPM */
+static char * undock_12_xpm[] = {
+"12 12 5 1",
+" c None",
+". c #000000",
+"+ c #5A5D5A",
+"@ c #FFFFFF",
+"# c #949194",
+" ",
+" ..... ",
+" +@@@+ ",
+" +@@@+..... ",
+" +@@@+####+ ",
+" +@@@+####+ ",
+" +@@@+####+ ",
+" +++++####+ ",
+" +#######+ ",
+" +#######+ ",
+" +++++++++ ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_in.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_in.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_in.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,34 @@
+/* XPM */
+static char * zoom_in_xpm[] = {
+"24 24 7 1",
+" c None",
+". c #000000",
+"+ c #949194",
+"@ c #DEDADE",
+"# c #FFFFFF",
+"$ c #D5D6D5",
+"% c #D6D1D6",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" +.@##$.+ ",
+" .##++##.+ ",
+" .@#+####@. ",
+" .#+######.+ ",
+" .########.+ ",
+" .@######@.+ ",
+" .######.++ ",
+" ...@##@.++ ",
+" ...+....++ ",
+" ...++ ++++ ",
+" ...++ .. ",
+" ...++ ..% ",
+" ...++ ...... ",
+" +.++ ......% ",
+" ++ %..%%% ",
+" ..% ",
+" %% ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_out.xpm
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_out.xpm 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Bitmaps/zoom_out.xpm 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,34 @@
+/* XPM */
+static char * zoom_out_xpm[] = {
+"24 24 7 1",
+" c None",
+". c #000000",
+"+ c #D6D1D6",
+"@ c #949194",
+"# c #DEDADE",
+"$ c #FFFFFF",
+"% c #D5D6D5",
+" ",
+" ",
+" ",
+" ",
+" .... ",
+" @.#$$%.@ ",
+" .$$@@$$.@ ",
+" .#$@$$$$#. ",
+" .$@$$$$$$.@ ",
+" .$$$$$$$$.@ ",
+" .#$$$$$$#.@ ",
+" .$$$$$$.@@ ",
+" ...#$$#.@@ ",
+" ... at ....@@ ",
+" ...@@ @@@@ ",
+" ...@@ ",
+" ...@@ ",
+" ...@@ ...... ",
+" @.@@ ......+ ",
+" @@ ++++++ ",
+" ",
+" ",
+" ",
+" "};
Added: packages/thuban/branches/upstream/current/Resources/Locale/de/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/de/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/es/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/es/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/fr/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/fr/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/hu/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/hu/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/it/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/it/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/pt_BR/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/pt_BR/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Locale/ru/LC_MESSAGES/thuban.mo
===================================================================
(Binary files differ)
Property changes on: packages/thuban/branches/upstream/current/Resources/Locale/ru/LC_MESSAGES/thuban.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: packages/thuban/branches/upstream/current/Resources/Projections/defaults.proj
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Projections/defaults.proj 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Projections/defaults.proj 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+<projectionlist>
+ <projection name="UTM Zone 27">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <projection name="Gauss-Krueger Zone 2 (Germany)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.0"/>
+ <parameter value="lon_0=6.0"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="k=1.0"/>
+ <parameter value="ellps=bessel"/>
+ </projection>
+ <projection name="UK National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=49"/>
+ <parameter value="lon_0=-2"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=-100000"/>
+ <parameter value="k=0.999601"/>
+ <parameter value="ellps=airy"/>
+ </projection>
+ <projection name="Geographic">
+ <parameter value="proj=latlong"/>
+ <parameter value="to_meter=0.017453292519943295"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <projection name="Belgian Datum 1972">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.83333339"/>
+ <parameter value="lat_2=51.16666723"/>
+ <parameter value="lat_0=90.0"/>
+ <parameter value="lon_0=4.367486667"/>
+ <parameter value="x_0=150000.013"/>
+ <parameter value="y_0=5400088.438"/>
+ <parameter value="ellps=intl"/>
+ </projection>
+ <projection name="Gauss-Boaga Zone 1 (Italy)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="k=0.9996"/>
+ <parameter value="ellps=intl"/>
+ </projection>
+ <projection name="Reseau geodesique francais (Lambert-93)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.0"/>
+ <parameter value="lat_2=49.0"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=3.0"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=66000000"/>
+ <parameter value="ellps=GRS80"/>
+ </projection>
+</projectionlist>
Added: packages/thuban/branches/upstream/current/Resources/Projections/epsg-deprecated.proj
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Projections/epsg-deprecated.proj 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Projections/epsg-deprecated.proj 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projfile SYSTEM "projectionlist.dtd">
+<projectionlist>
+ <projection epsg="31493" name="DHDN / Germany zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.000000000"/>
+ <parameter value="lon_0=9.000000000"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000.000"/>
+ <parameter value="y_0=0.000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ </projection>
+</projectionlist>
Added: packages/thuban/branches/upstream/current/Resources/Projections/epsg.proj
===================================================================
--- packages/thuban/branches/upstream/current/Resources/Projections/epsg.proj 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/Projections/epsg.proj 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,24981 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projfile SYSTEM "projectionlist.dtd">
+<projectionlist>
+ <projection epsg="2000" name="Anguilla 1957 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2001" name="Antigua 1943 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-255,-15,71,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2002" name="Dominica 1945 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=725,685,536,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2003" name="Grenada 1953 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=72,213.7,93,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2004" name="Montserrat 58 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=174,359,365,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2005" name="St Kitts 1955 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=9,183,236,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2006" name="St Lucia 1955 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-149,128,296,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2007" name="St Vincent 45 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2008" name="NAD27(CGQ77) / SCoPQ zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2009" name="NAD27(CGQ77) / SCoPQ zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-58.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2010" name="NAD27(CGQ77) / SCoPQ zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2011" name="NAD27(CGQ77) / SCoPQ zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2012" name="NAD27(CGQ77) / SCoPQ zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-67.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2013" name="NAD27(CGQ77) / SCoPQ zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2014" name="NAD27(CGQ77) / SCoPQ zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-73.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2015" name="NAD27(CGQ77) / SCoPQ zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-76.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2016" name="NAD27(CGQ77) / SCoPQ zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2017" name="NAD27(76) / MTM zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-73.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2018" name="NAD27(76) / MTM zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-76.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2019" name="NAD27(76) / MTM zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2020" name="NAD27(76) / MTM zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2021" name="NAD27(76) / MTM zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2022" name="NAD27(76) / MTM zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-84"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2023" name="NAD27(76) / MTM zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2024" name="NAD27(76) / MTM zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2025" name="NAD27(76) / MTM zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-93"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2026" name="NAD27(76) / MTM zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-96"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2027" name="NAD27(76) / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2028" name="NAD27(76) / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2029" name="NAD27(76) / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2030" name="NAD27(76) / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2031" name="NAD27(CGQ77) / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2032" name="NAD27(CGQ77) / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2033" name="NAD27(CGQ77) / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2034" name="NAD27(CGQ77) / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2035" name="NAD27(CGQ77) / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2036" name="NAD83(CSRS98) / New Brunswick Stereo">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-66.5"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=7500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2037" name="NAD83(CSRS98) / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2038" name="NAD83(CSRS98) / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2039" name="Israel / Israeli TM Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31.73439361111111"/>
+ <parameter value="lon_0=35.20451694444445"/>
+ <parameter value="k=1.000007"/>
+ <parameter value="x_0=219529.584"/>
+ <parameter value="y_0=626907.39"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2040" name="Locodjo 1965 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-125,53,467,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2041" name="Abidjan 1987 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-124.76,53,466.79,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2042" name="Locodjo 1965 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-125,53,467,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2043" name="Abidjan 1987 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-124.76,53,466.79,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2044" name="Hanoi 1972 / Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-17.51,-108.32,-62.39,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2045" name="Hanoi 1972 / Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-17.51,-108.32,-62.39,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2057" name="Rassadiran / Nakhl e Taqi">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=27.51882880555555"/>
+ <parameter value="lonc=52.60353916666667"/>
+ <parameter value="alpha=0.5716611944444444"/>
+ <parameter value="k=0.999895934"/>
+ <parameter value="x_0=658377.437"/>
+ <parameter value="y_0=3044969.194"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-133.63,-157.5,-158.62,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2058" name="ED50(ED77) / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2059" name="ED50(ED77) / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2060" name="ED50(ED77) / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2061" name="ED50(ED77) / UTM zone 41N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2062" name="Madrid 1870 (Madrid) / Spain">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-3.687938888888889"/>
+ <parameter value="k_0=0.9988085293"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=600000"/>
+ <parameter value="a=6378298.3"/>
+ <parameter value="b=6356657.142669562"/>
+ <parameter value="pm=madrid"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2063" name="Dabola 1981 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-23,259,-9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2064" name="Dabola 1981 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-23,259,-9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2065" name="S-JTSK (Ferro) / Krovak">
+ <parameter value="proj=krovak"/>
+ <parameter value="lat_0=49.5"/>
+ <parameter value="lon_0=24.83333333333333"/>
+ <parameter value="alpha=30.28813972222222"/>
+ <parameter value="k=0.9999"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2066" name="Mount Dillon / Tobago Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=11.25217861111111"/>
+ <parameter value="lon_0=-60.68600888888889"/>
+ <parameter value="x_0=37718.66154375"/>
+ <parameter value="y_0=36209.915082"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="to_meter=0.2011661949"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2067" name="Naparima 1955 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2068" name="ELD79 / Libya zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2069" name="ELD79 / Libya zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=11"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2070" name="ELD79 / Libya zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2071" name="ELD79 / Libya zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2072" name="ELD79 / Libya zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=17"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2073" name="ELD79 / Libya zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=19"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2074" name="ELD79 / Libya zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2075" name="ELD79 / Libya zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=23"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2076" name="ELD79 / Libya zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2077" name="ELD79 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2078" name="ELD79 / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2079" name="ELD79 / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2080" name="ELD79 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2081" name="Chos Malal 1914 / Argentina zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2082" name="Pampa del Castillo / Argentina zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2083" name="Hito XVIII 1963 / Argentina zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2084" name="Hito XVIII 1963 / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2085" name="NAD27 / Cuba Norte">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=22.35"/>
+ <parameter value="lat_0=22.35"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k_0=0.99993602"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=280296.016"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2086" name="NAD27 / Cuba Sur">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=20.71666666666667"/>
+ <parameter value="lat_0=20.71666666666667"/>
+ <parameter value="lon_0=-76.83333333333333"/>
+ <parameter value="k_0=0.99994848"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=229126.939"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2087" name="ELD79 / TM 12 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2088" name="Carthage / TM 11 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=11"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2089" name="Yemen NGN96 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2090" name="Yemen NGN96 / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2091" name="South Yemen / Gauss Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-76,-138,67,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2092" name="South Yemen / Gauss Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-76,-138,67,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2093" name="Hanoi 1972 / GK 106 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=106"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-17.51,-108.32,-62.39,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2094" name="WGS 72BE / TM 106 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=106"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2095" name="Bissau / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-173,253,27,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2096" name="Korean 1985 / Korea East Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2097" name="Korean 1985 / Korea Central Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=127"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2098" name="Korean 1985 / Korea West Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=125"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2099" name="Qatar 1948 / Qatar Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=25.38236111111111"/>
+ <parameter value="lon_0=50.76138888888889"/>
+ <parameter value="x_0=100000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2100" name="GGRS87 / Greek Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=-199.87,74.79,246.62,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2101" name="Lake / Maracaibo Grid M1">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10.16666666666667"/>
+ <parameter value="lat_0=10.16666666666667"/>
+ <parameter value="lon_0=-71.60561777777777"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=-52684.972"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2102" name="Lake / Maracaibo Grid">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10.16666666666667"/>
+ <parameter value="lat_0=10.16666666666667"/>
+ <parameter value="lon_0=-71.60561777777777"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=147315.028"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2103" name="Lake / Maracaibo Grid M3">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10.16666666666667"/>
+ <parameter value="lat_0=10.16666666666667"/>
+ <parameter value="lon_0=-71.60561777777777"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=447315.028"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2104" name="Lake / Maracaibo La Rosa Grid">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10.16666666666667"/>
+ <parameter value="lat_0=10.16666666666667"/>
+ <parameter value="lon_0=-71.60561777777777"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=-17044"/>
+ <parameter value="y_0=-23139.97"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2105" name="NZGD2000 / Mount Eden Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-36.87972222222222"/>
+ <parameter value="lon_0=174.7641666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2106" name="NZGD2000 / Bay of Plenty Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-37.76111111111111"/>
+ <parameter value="lon_0=176.4661111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2107" name="NZGD2000 / Poverty Bay Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-38.62444444444444"/>
+ <parameter value="lon_0=177.8855555555556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2108" name="NZGD2000 / Hawkes Bay Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.65083333333333"/>
+ <parameter value="lon_0=176.6736111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2109" name="NZGD2000 / Taranaki Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.13555555555556"/>
+ <parameter value="lon_0=174.2277777777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2110" name="NZGD2000 / Tuhirangi Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.51222222222222"/>
+ <parameter value="lon_0=175.64"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2111" name="NZGD2000 / Wanganui Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.24194444444444"/>
+ <parameter value="lon_0=175.4880555555555"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2112" name="NZGD2000 / Wairarapa Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.92527777777777"/>
+ <parameter value="lon_0=175.6472222222222"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2113" name="NZGD2000 / Wellington Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.3011111111111"/>
+ <parameter value="lon_0=174.7763888888889"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2114" name="NZGD2000 / Collingwood Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.71472222222223"/>
+ <parameter value="lon_0=172.6719444444444"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2115" name="NZGD2000 / Nelson Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.27444444444444"/>
+ <parameter value="lon_0=173.2991666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2116" name="NZGD2000 / Karamea Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.28972222222222"/>
+ <parameter value="lon_0=172.1088888888889"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2117" name="NZGD2000 / Buller Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.81055555555555"/>
+ <parameter value="lon_0=171.5811111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2118" name="NZGD2000 / Grey Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.33361111111111"/>
+ <parameter value="lon_0=171.5497222222222"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2119" name="NZGD2000 / Amuri Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.68888888888888"/>
+ <parameter value="lon_0=173.01"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2120" name="NZGD2000 / Marlborough Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.54444444444444"/>
+ <parameter value="lon_0=173.8019444444444"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2121" name="NZGD2000 / Hokitika Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.88611111111111"/>
+ <parameter value="lon_0=170.9797222222222"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2122" name="NZGD2000 / Okarito Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.11"/>
+ <parameter value="lon_0=170.2608333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2123" name="NZGD2000 / Jacksons Bay Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.97777777777778"/>
+ <parameter value="lon_0=168.6061111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2124" name="NZGD2000 / Mount Pleasant Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.59055555555556"/>
+ <parameter value="lon_0=172.7269444444445"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2125" name="NZGD2000 / Gawler Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.74861111111111"/>
+ <parameter value="lon_0=171.3605555555555"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2126" name="NZGD2000 / Timaru Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-44.40194444444445"/>
+ <parameter value="lon_0=171.0572222222222"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2127" name="NZGD2000 / Lindis Peak Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-44.735"/>
+ <parameter value="lon_0=169.4675"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2128" name="NZGD2000 / Mount Nicholas Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.13277777777778"/>
+ <parameter value="lon_0=168.3986111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2129" name="NZGD2000 / Mount York Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.56361111111111"/>
+ <parameter value="lon_0=167.7386111111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2130" name="NZGD2000 / Observation Point Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.81611111111111"/>
+ <parameter value="lon_0=170.6283333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2131" name="NZGD2000 / North Taieri Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.86138888888889"/>
+ <parameter value="lon_0=170.2825"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2132" name="NZGD2000 / Bluff Circuit 2000">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-46.6"/>
+ <parameter value="lon_0=168.3427777777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2133" name="NZGD2000 / UTM zone 58S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2134" name="NZGD2000 / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2135" name="NZGD2000 / UTM zone 60S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2136" name="Accra / Ghana National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.666666666666667"/>
+ <parameter value="lon_0=-1"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=274319.7391633579"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="towgs84=-199,32,322,0,0,0,0"/>
+ <parameter value="to_meter=0.3047997101815088"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2137" name="Accra / TM 1 NW">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-1"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="towgs84=-199,32,322,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2138" name="NAD27(CGQ77) / Quebec Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=60"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2139" name="NAD83(CSRS98) / SCoPQ zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2140" name="NAD83(CSRS98) / MTM zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-58.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2141" name="NAD83(CSRS98) / MTM zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2142" name="NAD83(CSRS98) / MTM zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2143" name="NAD83(CSRS98) / MTM zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-67.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2144" name="NAD83(CSRS98) / MTM zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2145" name="NAD83(CSRS98) / MTM zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-73.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2146" name="NAD83(CSRS98) / MTM zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-76.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2147" name="NAD83(CSRS98) / MTM zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2148" name="NAD83(CSRS98) / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2149" name="NAD83(CSRS98) / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2150" name="NAD83(CSRS98) / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2151" name="NAD83(CSRS98) / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2152" name="NAD83(CSRS98) / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2153" name="NAD83(CSRS98) / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2154" name="RGF93 / Lambert-93">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=44"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=3"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=6600000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2155" name="American Samoa 1962 / American Samoa Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=-14.26666666666667"/>
+ <parameter value="lat_0=-14.26666666666667"/>
+ <parameter value="lon_0=170"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="towgs84=-115,118,426,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2156" name="NAD83(HARN) / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2157" name="IRENET95 / Irish Transverse Mercator">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=53.5"/>
+ <parameter value="lon_0=-8"/>
+ <parameter value="k=0.999820"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=750000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2158" name="IRENET95 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2159" name="Sierra Leone 1924 / New Colony Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=6.666666666666667"/>
+ <parameter value="lon_0=-12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=152399.8550907544"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="to_meter=0.3047997101815088"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2160" name="Sierra Leone 1924 / New War Office Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=6.666666666666667"/>
+ <parameter value="lon_0=-12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=243839.7681452071"/>
+ <parameter value="y_0=182879.8261089053"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="to_meter=0.3047997101815088"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2161" name="Sierra Leone 1968 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-88,4,101,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2162" name="Sierra Leone 1968 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-88,4,101,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2163" name="US National Atlas Equal Area">
+ <parameter value="proj=laea"/>
+ <parameter value="lat_0=45"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6370997"/>
+ <parameter value="b=6370997"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2164" name="Locodjo 1965 / TM 5 NW">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-5"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-125,53,467,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2165" name="Abidjan 1987 / TM 5 NW">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-5"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-124.76,53,466.79,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2166" name="Pulkovo 1942(83) / Gauss Kruger zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2167" name="Pulkovo 1942(83) / Gauss Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2168" name="Pulkovo 1942(83) / Gauss Kruger zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2169" name="Luxembourg 1930 / Gauss">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=49.83333333333334"/>
+ <parameter value="lon_0=6.166666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=80000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-193,13.7,-39.3,-0.41,-2.933,2.688,0.43"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2170" name="MGI / Slovenia Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2171" name="Pulkovo 1942(58) / Poland zone I">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=50.625"/>
+ <parameter value="lon_0=21.08333333333333"/>
+ <parameter value="k=0.999800"/>
+ <parameter value="x_0=4637000"/>
+ <parameter value="y_0=5647000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2172" name="Pulkovo 1942(58) / Poland zone II">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=53.00194444444445"/>
+ <parameter value="lon_0=21.50277777777778"/>
+ <parameter value="k=0.999800"/>
+ <parameter value="x_0=4603000"/>
+ <parameter value="y_0=5806000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2173" name="Pulkovo 1942(58) / Poland zone III">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=53.58333333333334"/>
+ <parameter value="lon_0=17.00833333333333"/>
+ <parameter value="k=0.999800"/>
+ <parameter value="x_0=3501000"/>
+ <parameter value="y_0=5999000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2174" name="Pulkovo 1942(58) / Poland zone IV">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=51.67083333333333"/>
+ <parameter value="lon_0=16.67222222222222"/>
+ <parameter value="k=0.999800"/>
+ <parameter value="x_0=3703000"/>
+ <parameter value="y_0=5627000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2175" name="Pulkovo 1942(58) / Poland zone V">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=18.95833333333333"/>
+ <parameter value="k=0.999983"/>
+ <parameter value="x_0=237000"/>
+ <parameter value="y_0=-4700000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2176" name="ETRS89 / Poland CS2000 zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=0.999923"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2177" name="ETRS89 / Poland CS2000 zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=18"/>
+ <parameter value="k=0.999923"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2178" name="ETRS89 / Poland CS2000 zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=0.999923"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2179" name="ETRS89 / Poland CS2000 zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=0.999923"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2180" name="ETRS89 / Poland CS92">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=19"/>
+ <parameter value="k=0.999300"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=-5300000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2188" name="Azores Occidental 1939 / UTM zone 25N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2189" name="Azores Central 1948 / UTM zone 26N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2190" name="Azores Oriental 1940 / UTM zone 26N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2191" name="Madeira 1936 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2192" name="ED50 / France EuroLambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.8"/>
+ <parameter value="lat_0=46.8"/>
+ <parameter value="lon_0=2.337229166666667"/>
+ <parameter value="k_0=0.99987742"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2200000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2193" name="NZGD2000 / New Zealand Transverse Mercator">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=173"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=1600000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2194" name="American Samoa 1962 / American Samoa Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=-14.26666666666667"/>
+ <parameter value="lat_0=-14.26666666666667"/>
+ <parameter value="lon_0=-170"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="towgs84=-115,118,426,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2195" name="NAD83(HARN) / UTM zone 2S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2196" name="ETRS89 / Kp2000 Jutland">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9.5"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2197" name="ETRS89 / Kp2000 Zealand">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2198" name="ETRS89 / Kp2000 Bornholm">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2199" name="Albanian 1987 / Gauss Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2200" name="ATS77 / New Brunswick Stereographic (ATS77)">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-66.5"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2201" name="REGVEN / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2202" name="REGVEN / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2203" name="REGVEN / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2204" name="NAD27 / Tennessee">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.25"/>
+ <parameter value="lat_2=36.41666666666666"/>
+ <parameter value="lat_0=34.66666666666666"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=30480.06096012192"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2205" name="NAD83 / Kentucky North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=38.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2206" name="ED50 / 3-degree Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2207" name="ED50 / 3-degree Gauss-Kruger zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=10500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2208" name="ED50 / 3-degree Gauss-Kruger zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=11500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2209" name="ED50 / 3-degree Gauss-Kruger zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=12500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2210" name="ED50 / 3-degree Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2211" name="ED50 / 3-degree Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2212" name="ED50 / 3-degree Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2213" name="ETRS89 / TM 30 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2214" name="Douala 1948 / AOF west">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=10.5"/>
+ <parameter value="k=0.999000"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2215" name="Manoca 1962 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-70.9,-151.8,-41.4,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2216" name="Qornoq 1927 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2217" name="Qornoq 1927 / UTM zone 23N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2219" name="ATS77 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2220" name="ATS77 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2222" name="NAD83 / Arizona East (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-110.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2223" name="NAD83 / Arizona Central (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-111.9166666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2224" name="NAD83 / Arizona West (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-113.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2225" name="NAD83 / California zone 1 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.66666666666666"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2226" name="NAD83 / California zone 2 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.83333333333334"/>
+ <parameter value="lat_2=38.33333333333334"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2227" name="NAD83 / California zone 3 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.06666666666667"/>
+ <parameter value="lat_0=36.5"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2228" name="NAD83 / California zone 4 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.25"/>
+ <parameter value="lat_2=36"/>
+ <parameter value="lat_0=35.33333333333334"/>
+ <parameter value="lon_0=-119"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2229" name="NAD83 / California zone 5 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.46666666666667"/>
+ <parameter value="lat_2=34.03333333333333"/>
+ <parameter value="lat_0=33.5"/>
+ <parameter value="lon_0=-118"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2230" name="NAD83 / California zone 6 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.88333333333333"/>
+ <parameter value="lat_2=32.78333333333333"/>
+ <parameter value="lat_0=32.16666666666666"/>
+ <parameter value="lon_0=-116.25"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2231" name="NAD83 / Colorado North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.78333333333333"/>
+ <parameter value="lat_2=39.71666666666667"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2232" name="NAD83 / Colorado Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.75"/>
+ <parameter value="lat_2=38.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2233" name="NAD83 / Colorado South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.23333333333333"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2234" name="NAD83 / Connecticut (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.86666666666667"/>
+ <parameter value="lat_2=41.2"/>
+ <parameter value="lat_0=40.83333333333334"/>
+ <parameter value="lon_0=-72.75"/>
+ <parameter value="x_0=304800.6096012192"/>
+ <parameter value="y_0=152400.3048006096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2235" name="NAD83 / Delaware (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-75.41666666666667"/>
+ <parameter value="k=0.999995"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2236" name="NAD83 / Florida East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2237" name="NAD83 / Florida West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-82"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2238" name="NAD83 / Florida North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.75"/>
+ <parameter value="lat_2=29.58333333333333"/>
+ <parameter value="lat_0=29"/>
+ <parameter value="lon_0=-84.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2239" name="NAD83 / Georgia East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-82.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2240" name="NAD83 / Georgia West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-84.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2241" name="NAD83 / Idaho East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-112.1666666666667"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2242" name="NAD83 / Idaho Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-114"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2243" name="NAD83 / Idaho West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-115.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=800000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2244" name="NAD83 / Indiana East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-85.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=99999.99989839978"/>
+ <parameter value="y_0=249364.9987299975"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2245" name="NAD83 / Indiana West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-87.08333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=249364.9987299975"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2246" name="NAD83 / Kentucky North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=38.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2247" name="NAD83 / Kentucky South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.93333333333333"/>
+ <parameter value="lat_2=36.73333333333333"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2248" name="NAD83 / Maryland (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.45"/>
+ <parameter value="lat_2=38.3"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="x_0=399999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2249" name="NAD83 / Massachusetts Mainland (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.68333333333333"/>
+ <parameter value="lat_2=41.71666666666667"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=750000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2250" name="NAD83 / Massachusetts Island (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.48333333333333"/>
+ <parameter value="lat_2=41.28333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2251" name="NAD83 / Michigan North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.08333333333334"/>
+ <parameter value="lat_2=45.48333333333333"/>
+ <parameter value="lat_0=44.78333333333333"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="x_0=7999999.999968001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2252" name="NAD83 / Michigan Central (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.7"/>
+ <parameter value="lat_2=44.18333333333333"/>
+ <parameter value="lat_0=43.31666666666667"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=5999999.999976001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2253" name="NAD83 / Michigan South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.66666666666666"/>
+ <parameter value="lat_2=42.1"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=3999999.999984"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2254" name="NAD83 / Mississippi East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-88.83333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2255" name="NAD83 / Mississippi West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2256" name="NAD83 / Montana (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=45"/>
+ <parameter value="lat_0=44.25"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2257" name="NAD83 / New Mexico East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-104.3333333333333"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=165000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2258" name="NAD83 / New Mexico Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-106.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2259" name="NAD83 / New Mexico West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-107.8333333333333"/>
+ <parameter value="k=0.999917"/>
+ <parameter value="x_0=830000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2260" name="NAD83 / New York East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2261" name="NAD83 / New York Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-76.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=249999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2262" name="NAD83 / New York West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-78.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=350000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2263" name="NAD83 / New York Long Island (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.03333333333333"/>
+ <parameter value="lat_2=40.66666666666666"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-74"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2264" name="NAD83 / North Carolina (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.16666666666666"/>
+ <parameter value="lat_2=34.33333333333334"/>
+ <parameter value="lat_0=33.75"/>
+ <parameter value="lon_0=-79"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2265" name="NAD83 / North Dakota North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.43333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2266" name="NAD83 / North Dakota South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.48333333333333"/>
+ <parameter value="lat_2=46.18333333333333"/>
+ <parameter value="lat_0=45.66666666666666"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2267" name="NAD83 / Oklahoma North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.76666666666667"/>
+ <parameter value="lat_2=35.56666666666667"/>
+ <parameter value="lat_0=35"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2268" name="NAD83 / Oklahoma South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.23333333333333"/>
+ <parameter value="lat_2=33.93333333333333"/>
+ <parameter value="lat_0=33.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2269" name="NAD83 / Oregon North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46"/>
+ <parameter value="lat_2=44.33333333333334"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2500000.0001424"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2270" name="NAD83 / Oregon South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44"/>
+ <parameter value="lat_2=42.33333333333334"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=1500000.0001464"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2271" name="NAD83 / Pennsylvania North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.95"/>
+ <parameter value="lat_2=40.88333333333333"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2272" name="NAD83 / Pennsylvania South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.96666666666667"/>
+ <parameter value="lat_2=39.93333333333333"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2273" name="NAD83 / South Carolina (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.83333333333334"/>
+ <parameter value="lat_2=32.5"/>
+ <parameter value="lat_0=31.83333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=609600"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2274" name="NAD83 / Tennessee (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.41666666666666"/>
+ <parameter value="lat_2=35.25"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2275" name="NAD83 / Texas North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.18333333333333"/>
+ <parameter value="lat_2=34.65"/>
+ <parameter value="lat_0=34"/>
+ <parameter value="lon_0=-101.5"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=999999.9998983998"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2276" name="NAD83 / Texas North Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.96666666666667"/>
+ <parameter value="lat_2=32.13333333333333"/>
+ <parameter value="lat_0=31.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2277" name="NAD83 / Texas Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=31.88333333333333"/>
+ <parameter value="lat_2=30.11666666666667"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2278" name="NAD83 / Texas South Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.28333333333333"/>
+ <parameter value="lat_2=28.38333333333333"/>
+ <parameter value="lat_0=27.83333333333333"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=3999999.9998984"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2279" name="NAD83 / Texas South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=27.83333333333333"/>
+ <parameter value="lat_2=26.16666666666667"/>
+ <parameter value="lat_0=25.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=5000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2280" name="NAD83 / Utah North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.71666666666667"/>
+ <parameter value="lat_0=40.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=999999.9999960001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2281" name="NAD83 / Utah Central (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.65"/>
+ <parameter value="lat_2=39.01666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=1999999.999992"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2282" name="NAD83 / Utah South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.35"/>
+ <parameter value="lat_2=37.21666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=2999999.999988"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2283" name="NAD83 / Virginia North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.2"/>
+ <parameter value="lat_2=38.03333333333333"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000.0001016"/>
+ <parameter value="y_0=2000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2284" name="NAD83 / Virginia South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=36.76666666666667"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000.0001016"/>
+ <parameter value="y_0=999999.9998983998"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2285" name="NAD83 / Washington North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.5"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-120.8333333333333"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2286" name="NAD83 / Washington South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.33333333333334"/>
+ <parameter value="lat_2=45.83333333333334"/>
+ <parameter value="lat_0=45.33333333333334"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2287" name="NAD83 / Wisconsin North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.76666666666667"/>
+ <parameter value="lat_2=45.56666666666667"/>
+ <parameter value="lat_0=45.16666666666666"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2288" name="NAD83 / Wisconsin Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.5"/>
+ <parameter value="lat_2=44.25"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2289" name="NAD83 / Wisconsin South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.06666666666667"/>
+ <parameter value="lat_2=42.73333333333333"/>
+ <parameter value="lat_0=42"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2290" name="ATS77 / Prince Edward Isl. Stereographic (ATS77)">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=47.25"/>
+ <parameter value="lon_0=-63"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2291" name="NAD83(CSRS98) / Prince Edward Isl. Stereographic (NAD83)">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=47.25"/>
+ <parameter value="lon_0=-63"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2292" name="NAD83(CSRS98) / Prince Edward Isl. Stereographic (NAD83)">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=47.25"/>
+ <parameter value="lon_0=-63"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2294" name="ATS77 / MTM Nova Scotia zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2295" name="ATS77 / MTM Nova Scotia zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2308" name="Batavia / TM 109 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=109"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2309" name="WGS 84 / TM 116 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=116"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2310" name="WGS 84 / TM 132 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2311" name="WGS 84 / TM 6 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=6"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2312" name="Garoua / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2313" name="Kousseri / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2314" name="Trinidad 1903 / Trinidad Grid (ftCla)">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=10.44166666666667"/>
+ <parameter value="lon_0=-61.33333333333334"/>
+ <parameter value="x_0=86501.46380699999"/>
+ <parameter value="y_0=65379.01334249999"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="towgs84=-61.702,284.488,472.052,0,0,0,0"/>
+ <parameter value="to_meter=0.304797265"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2315" name="Campo Inchauspe / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2316" name="Campo Inchauspe / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2317" name="PSAD56 / ICN Regional">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=9"/>
+ <parameter value="lat_2=3"/>
+ <parameter value="lat_0=6"/>
+ <parameter value="lon_0=-66"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2318" name="Ain el Abd / Aramco Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=17"/>
+ <parameter value="lat_2=33"/>
+ <parameter value="lat_0=25.08951"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2319" name="ED50 / TM27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2320" name="ED50 / TM30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2321" name="ED50 / TM33">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2322" name="ED50 / TM36">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2323" name="ED50 / TM39">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2324" name="ED50 / TM42">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2325" name="ED50 / TM45">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2326" name="Hong Kong 1980 Grid System">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=22.31213333333334"/>
+ <parameter value="lon_0=114.1785555555556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=836694.05"/>
+ <parameter value="y_0=819069.8"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-162.619,-276.959,-161.764,0.067753,-2.24365,-1.15883,-1.09425"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2327" name="Xian 1980 / Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2328" name="Xian 1980 / Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2329" name="Xian 1980 / Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2330" name="Xian 1980 / Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2331" name="Xian 1980 / Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2332" name="Xian 1980 / Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2333" name="Xian 1980 / Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2334" name="Xian 1980 / Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2335" name="Xian 1980 / Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2336" name="Xian 1980 / Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2337" name="Xian 1980 / Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2338" name="Xian 1980 / Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2339" name="Xian 1980 / Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2340" name="Xian 1980 / Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2341" name="Xian 1980 / Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2342" name="Xian 1980 / Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2343" name="Xian 1980 / Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2344" name="Xian 1980 / Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2345" name="Xian 1980 / Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2346" name="Xian 1980 / Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2347" name="Xian 1980 / Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2348" name="Xian 1980 / Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2349" name="Xian 1980 / 3-degree Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2350" name="Xian 1980 / 3-degree Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2351" name="Xian 1980 / 3-degree Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2352" name="Xian 1980 / 3-degree Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2353" name="Xian 1980 / 3-degree Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2354" name="Xian 1980 / 3-degree Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2355" name="Xian 1980 / 3-degree Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2356" name="Xian 1980 / 3-degree Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2357" name="Xian 1980 / 3-degree Gauss-Kruger zone 33">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=33500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2358" name="Xian 1980 / 3-degree Gauss-Kruger zone 34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=34500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2359" name="Xian 1980 / 3-degree Gauss-Kruger zone 35">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=35500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2360" name="Xian 1980 / 3-degree Gauss-Kruger zone 36">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=36500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2361" name="Xian 1980 / 3-degree Gauss-Kruger zone 37">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=37500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2362" name="Xian 1980 / 3-degree Gauss-Kruger zone 38">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=38500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2363" name="Xian 1980 / 3-degree Gauss-Kruger zone 39">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=39500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2364" name="Xian 1980 / 3-degree Gauss-Kruger zone 40">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=40500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2365" name="Xian 1980 / 3-degree Gauss-Kruger zone 41">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=41500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2366" name="Xian 1980 / 3-degree Gauss-Kruger zone 42">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=42500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2367" name="Xian 1980 / 3-degree Gauss-Kruger zone 43">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=43500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2368" name="Xian 1980 / 3-degree Gauss-Kruger zone 44">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=44500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2369" name="Xian 1980 / 3-degree Gauss-Kruger zone 45">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=45500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2370" name="Xian 1980 / 3-degree Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2371" name="Xian 1980 / 3-degree Gauss-Kruger CM 78E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2372" name="Xian 1980 / 3-degree Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2373" name="Xian 1980 / 3-degree Gauss-Kruger CM 84E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2374" name="Xian 1980 / 3-degree Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2375" name="Xian 1980 / 3-degree Gauss-Kruger CM 90E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2376" name="Xian 1980 / 3-degree Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2377" name="Xian 1980 / 3-degree Gauss-Kruger CM 96E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2378" name="Xian 1980 / 3-degree Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2379" name="Xian 1980 / 3-degree Gauss-Kruger CM 102E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2380" name="Xian 1980 / 3-degree Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2381" name="Xian 1980 / 3-degree Gauss-Kruger CM 108E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2382" name="Xian 1980 / 3-degree Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2383" name="Xian 1980 / 3-degree Gauss-Kruger CM 114E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2384" name="Xian 1980 / 3-degree Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2385" name="Xian 1980 / 3-degree Gauss-Kruger CM 120E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2386" name="Xian 1980 / 3-degree Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2387" name="Xian 1980 / 3-degree Gauss-Kruger CM 126E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2388" name="Xian 1980 / 3-degree Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2389" name="Xian 1980 / 3-degree Gauss-Kruger CM 132E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2390" name="Xian 1980 / 3-degree Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2391" name="KKJ / Finland zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2392" name="KKJ / Finland zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2393" name="KKJ / Finland Uniform Coordinate System">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2394" name="KKJ / Finland zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2395" name="South Yemen / Gauss-Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-76,-138,67,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2396" name="South Yemen / Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-76,-138,67,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2397" name="Pulkovo 1942(83) / Gauss-Kruger zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2398" name="Pulkovo 1942(83) / Gauss-Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2399" name="Pulkovo 1942(83) / Gauss-Kruger zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2400" name="RT90 2.5 gon W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15.80827777777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2401" name="Beijing 1954 / 3-degree Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2402" name="Beijing 1954 / 3-degree Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2403" name="Beijing 1954 / 3-degree Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2404" name="Beijing 1954 / 3-degree Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2405" name="Beijing 1954 / 3-degree Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2406" name="Beijing 1954 / 3-degree Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2407" name="Beijing 1954 / 3-degree Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2408" name="Beijing 1954 / 3-degree Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2409" name="Beijing 1954 / 3-degree Gauss-Kruger zone 33">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=33500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2410" name="Beijing 1954 / 3-degree Gauss-Kruger zone 34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=34500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2411" name="Beijing 1954 / 3-degree Gauss-Kruger zone 35">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=35500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2412" name="Beijing 1954 / 3-degree Gauss-Kruger zone 36">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=36500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2413" name="Beijing 1954 / 3-degree Gauss-Kruger zone 37">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=37500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2414" name="Beijing 1954 / 3-degree Gauss-Kruger zone 38">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=38500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2415" name="Beijing 1954 / 3-degree Gauss-Kruger zone 39">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=39500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2416" name="Beijing 1954 / 3-degree Gauss-Kruger zone 40">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=40500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2417" name="Beijing 1954 / 3-degree Gauss-Kruger zone 41">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=41500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2418" name="Beijing 1954 / 3-degree Gauss-Kruger zone 42">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=42500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2419" name="Beijing 1954 / 3-degree Gauss-Kruger zone 43">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=43500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2420" name="Beijing 1954 / 3-degree Gauss-Kruger zone 44">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=44500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2421" name="Beijing 1954 / 3-degree Gauss-Kruger zone 45">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=45500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2422" name="Beijing 1954 / 3-degree Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2423" name="Beijing 1954 / 3-degree Gauss-Kruger CM 78E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2424" name="Beijing 1954 / 3-degree Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2425" name="Beijing 1954 / 3-degree Gauss-Kruger CM 84E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2426" name="Beijing 1954 / 3-degree Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2427" name="Beijing 1954 / 3-degree Gauss-Kruger CM 90E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2428" name="Beijing 1954 / 3-degree Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2429" name="Beijing 1954 / 3-degree Gauss-Kruger CM 96E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2430" name="Beijing 1954 / 3-degree Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2431" name="Beijing 1954 / 3-degree Gauss-Kruger CM 102E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2432" name="Beijing 1954 / 3-degree Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2433" name="Beijing 1954 / 3-degree Gauss-Kruger CM 108E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2434" name="Beijing 1954 / 3-degree Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2435" name="Beijing 1954 / 3-degree Gauss-Kruger CM 114E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2436" name="Beijing 1954 / 3-degree Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2437" name="Beijing 1954 / 3-degree Gauss-Kruger CM 120E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2438" name="Beijing 1954 / 3-degree Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2439" name="Beijing 1954 / 3-degree Gauss-Kruger CM 126E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2440" name="Beijing 1954 / 3-degree Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2441" name="Beijing 1954 / 3-degree Gauss-Kruger CM 132E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2442" name="Beijing 1954 / 3-degree Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2443" name="JGD2000 / Japan Plane Rectangular CS I">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=129.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2444" name="JGD2000 / Japan Plane Rectangular CS II">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=131"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2445" name="JGD2000 / Japan Plane Rectangular CS III">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=132.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2446" name="JGD2000 / Japan Plane Rectangular CS IV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=133.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2447" name="JGD2000 / Japan Plane Rectangular CS V">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=134.3333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2448" name="JGD2000 / Japan Plane Rectangular CS VI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=136"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2449" name="JGD2000 / Japan Plane Rectangular CS VII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=137.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2450" name="JGD2000 / Japan Plane Rectangular CS VIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=138.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2451" name="JGD2000 / Japan Plane Rectangular CS IX">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=139.8333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2452" name="JGD2000 / Japan Plane Rectangular CS X">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=140.8333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2453" name="JGD2000 / Japan Plane Rectangular CS XI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=140.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2454" name="JGD2000 / Japan Plane Rectangular CS XII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=142.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2455" name="JGD2000 / Japan Plane Rectangular CS XIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=144.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2456" name="JGD2000 / Japan Plane Rectangular CS XIV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=142"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2457" name="JGD2000 / Japan Plane Rectangular CS XV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=127.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2458" name="JGD2000 / Japan Plane Rectangular CS XVI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=124"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2459" name="JGD2000 / Japan Plane Rectangular CS XVII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=131"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2460" name="JGD2000 / Japan Plane Rectangular CS XVIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=20"/>
+ <parameter value="lon_0=136"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2461" name="JGD2000 / Japan Plane Rectangular CS XIX">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=154"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2462" name="Albanian 1987 / Gauss-Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2463" name="Pulkovo 1995 / Gauss-Kruger CM 21E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2464" name="Pulkovo 1995 / Gauss-Kruger CM 27E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2465" name="Pulkovo 1995 / Gauss-Kruger CM 33E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2466" name="Pulkovo 1995 / Gauss-Kruger CM 39E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2467" name="Pulkovo 1995 / Gauss-Kruger CM 45E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2468" name="Pulkovo 1995 / Gauss-Kruger CM 51E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2469" name="Pulkovo 1995 / Gauss-Kruger CM 57E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2470" name="Pulkovo 1995 / Gauss-Kruger CM 63E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2471" name="Pulkovo 1995 / Gauss-Kruger CM 69E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2472" name="Pulkovo 1995 / Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2473" name="Pulkovo 1995 / Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2474" name="Pulkovo 1995 / Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2475" name="Pulkovo 1995 / Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2476" name="Pulkovo 1995 / Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2477" name="Pulkovo 1995 / Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2478" name="Pulkovo 1995 / Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2479" name="Pulkovo 1995 / Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2480" name="Pulkovo 1995 / Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2481" name="Pulkovo 1995 / Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2482" name="Pulkovo 1995 / Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2483" name="Pulkovo 1995 / Gauss-Kruger CM 141E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2484" name="Pulkovo 1995 / Gauss-Kruger CM 147E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2485" name="Pulkovo 1995 / Gauss-Kruger CM 153E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2486" name="Pulkovo 1995 / Gauss-Kruger CM 159E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2487" name="Pulkovo 1995 / Gauss-Kruger CM 165E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2488" name="Pulkovo 1995 / Gauss-Kruger CM 171E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2489" name="Pulkovo 1995 / Gauss-Kruger CM 177E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2490" name="Pulkovo 1995 / Gauss-Kruger CM 177W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2491" name="Pulkovo 1995 / Gauss-Kruger CM 171W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2492" name="Pulkovo 1942 / Gauss-Kruger CM 9E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2493" name="Pulkovo 1942 / Gauss-Kruger CM 15E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2494" name="Pulkovo 1942 / Gauss-Kruger CM 21E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2495" name="Pulkovo 1942 / Gauss-Kruger CM 27E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2496" name="Pulkovo 1942 / Gauss-Kruger CM 33E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2497" name="Pulkovo 1942 / Gauss-Kruger CM 39E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2498" name="Pulkovo 1942 / Gauss-Kruger CM 45E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2499" name="Pulkovo 1942 / Gauss-Kruger CM 51E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2500" name="Pulkovo 1942 / Gauss-Kruger CM 57E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2501" name="Pulkovo 1942 / Gauss-Kruger CM 63E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2502" name="Pulkovo 1942 / Gauss-Kruger CM 69E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2503" name="Pulkovo 1942 / Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2504" name="Pulkovo 1942 / Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2505" name="Pulkovo 1942 / Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2506" name="Pulkovo 1942 / Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2507" name="Pulkovo 1942 / Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2508" name="Pulkovo 1942 / Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2509" name="Pulkovo 1942 / Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2510" name="Pulkovo 1942 / Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2511" name="Pulkovo 1942 / Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2512" name="Pulkovo 1942 / Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2513" name="Pulkovo 1942 / Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2514" name="Pulkovo 1942 / Gauss-Kruger CM 141E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2515" name="Pulkovo 1942 / Gauss-Kruger CM 147E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2516" name="Pulkovo 1942 / Gauss-Kruger CM 153E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2517" name="Pulkovo 1942 / Gauss-Kruger CM 159E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2518" name="Pulkovo 1942 / Gauss-Kruger CM 165E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2519" name="Pulkovo 1942 / Gauss-Kruger CM 171E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2520" name="Pulkovo 1942 / Gauss-Kruger CM 177E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2521" name="Pulkovo 1942 / Gauss-Kruger CM 177W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2522" name="Pulkovo 1942 / Gauss-Kruger CM 171W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2523" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2524" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2525" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2526" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=10500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2527" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=11500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2528" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=12500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2529" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2530" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2531" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2532" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2533" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2534" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=54"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2535" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2536" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=60"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2537" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2538" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=66"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2539" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2540" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 24">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=72"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=24500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2541" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2542" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2543" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2544" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2545" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2546" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2547" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2548" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2549" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 33">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=33500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2550" name="Samboja / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-404.78,685.68,45.47,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2551" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=34500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2552" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 35">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=35500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2553" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 36">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=36500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2554" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 37">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=37500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2555" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 38">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=38500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2556" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 39">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=39500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2557" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 40">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=40500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2558" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 41">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=41500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2559" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 42">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=42500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2560" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 43">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=43500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2561" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 44">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=44500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2562" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 45">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=45500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2563" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 46">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=138"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=46500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2564" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 47">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=47500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2565" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 48">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=144"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=48500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2566" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 49">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=49500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2567" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 50">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=150"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=50500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2568" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 51">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=51500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2569" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 52">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=156"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=52500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2570" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 53">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=53500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2571" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 54">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=162"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=54500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2572" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 55">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=55500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2573" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 56">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=56500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2574" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 57">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=57500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2575" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 58">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=58500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2576" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 59">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=59500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2577" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 60">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=180"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=60000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2578" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 61">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=61500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2579" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 62">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=62500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2580" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 63">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=63500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2581" name="Pulkovo 1942 / 3-degree Gauss-Kruger zone 64">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=64500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2582" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 21E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2583" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 24E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2584" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 27E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2585" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 30E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2586" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 33E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2587" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 36E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2588" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 39E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2589" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 42E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2590" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 45E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2591" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 48E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2592" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 51E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2593" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 54E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=54"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2594" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 57E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2595" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 60E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=60"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2596" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 63E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2597" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 66E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=66"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2598" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 69E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2599" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 72E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=72"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2600" name="Lietuvos Koordinoei Sistema 1994">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=0.999800"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2601" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2602" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 78E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2603" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2604" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 84E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2605" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2606" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 90E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2607" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2608" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 96E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2609" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2610" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 102E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2611" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2612" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 108E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2613" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2614" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 114E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2615" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2616" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 120E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2617" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2618" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 126E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2619" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2620" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 132E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2621" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2622" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 138E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=138"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2623" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 141E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2624" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 144E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=144"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2625" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 147E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2626" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 150E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=150"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2627" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 153E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2628" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 156E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=156"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2629" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 159E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2630" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 162E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=162"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2631" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 165E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2632" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 168E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2633" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 171E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2634" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 174E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2635" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 177E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2636" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 180E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=180"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2637" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 177W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2638" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 174W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2639" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 171W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2640" name="Pulkovo 1942 / 3-degree Gauss-Kruger CM 168W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2641" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2642" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2643" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2644" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=10500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2645" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=11500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2646" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=12500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2647" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2648" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2649" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2650" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2651" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2652" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=54"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2653" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2654" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=60"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2655" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2656" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=66"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2657" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2658" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 24">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=72"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=24500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2659" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2660" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2661" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2662" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2663" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2664" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2665" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2666" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2667" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 33">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=33500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2668" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=34500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2669" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 35">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=35500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2670" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 36">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=36500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2671" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 37">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=37500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2672" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 38">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=38500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2673" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 39">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=39500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2674" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 40">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=40500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2675" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 41">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=41500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2676" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 42">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=42500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2677" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 43">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=43500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2678" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 44">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=44500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2679" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 45">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=45500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2680" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 46">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=138"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=46500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2681" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 47">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=47500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2682" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 48">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=144"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=48500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2683" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 49">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=49500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2684" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 50">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=150"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=50500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2685" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 51">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=51500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2686" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 52">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=156"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=52500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2687" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 53">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=53500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2688" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 54">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=162"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=54500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2689" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 55">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=55500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2690" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 56">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=56500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2691" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 57">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=57500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2692" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 58">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=58500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2693" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 59">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=59500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2694" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 60">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=180"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=60000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2695" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 61">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=61500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2696" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 62">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=62500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2697" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 63">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=63500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2698" name="Pulkovo 1995 / 3-degree Gauss-Kruger zone 64">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=64500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2699" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 21E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2700" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 24E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2701" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 27E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2702" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 30E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=30"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2703" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 33E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2704" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 36E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2705" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 39E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2706" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 42E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=42"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2707" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 45E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2708" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 48E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2709" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 51E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2710" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 54E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=54"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2711" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 57E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2712" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 60E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=60"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2713" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 63E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2714" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 66E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=66"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2715" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 69E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2716" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 72E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=72"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2717" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2718" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 78E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=78"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2719" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2720" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 84E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=84"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2721" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2722" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 90E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2723" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2724" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 96E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=96"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2725" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2726" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 102E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=102"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2727" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2728" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 108E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=108"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2729" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2730" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 114E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=114"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2731" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2732" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 120E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=120"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2733" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2734" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 126E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=126"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2735" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2736" name="Tete / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2737" name="Tete / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2738" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 132E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=132"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2739" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2740" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 138E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=138"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2741" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 141E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2742" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 144E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=144"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2743" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 147E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2744" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 150E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=150"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2745" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 153E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2746" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 156E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=156"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2747" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 159E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2748" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 162E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=162"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2749" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 165E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2750" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 168E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2751" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 171E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2752" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 174E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2753" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 177E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2754" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 180E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=180"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2755" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 177W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2756" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 174W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-174"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2757" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 171W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2758" name="Pulkovo 1995 / 3-degree Gauss-Kruger CM 168W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-168"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2759" name="NAD83(HARN) / Alabama East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-85.83333333333333"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2760" name="NAD83(HARN) / Alabama West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-87.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2761" name="NAD83(HARN) / Arizona East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-110.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2762" name="NAD83(HARN) / Arizona Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-111.9166666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2763" name="NAD83(HARN) / Arizona West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-113.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2764" name="NAD83(HARN) / Arkansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.23333333333333"/>
+ <parameter value="lat_2=34.93333333333333"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2765" name="NAD83(HARN) / Arkansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.76666666666667"/>
+ <parameter value="lat_2=33.3"/>
+ <parameter value="lat_0=32.66666666666666"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2766" name="NAD83(HARN) / California zone 1">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.66666666666666"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2767" name="NAD83(HARN) / California zone 2">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.83333333333334"/>
+ <parameter value="lat_2=38.33333333333334"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2768" name="NAD83(HARN) / California zone 3">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.06666666666667"/>
+ <parameter value="lat_0=36.5"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2769" name="NAD83(HARN) / California zone 4">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.25"/>
+ <parameter value="lat_2=36"/>
+ <parameter value="lat_0=35.33333333333334"/>
+ <parameter value="lon_0=-119"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2770" name="NAD83(HARN) / California zone 5">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.46666666666667"/>
+ <parameter value="lat_2=34.03333333333333"/>
+ <parameter value="lat_0=33.5"/>
+ <parameter value="lon_0=-118"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2771" name="NAD83(HARN) / California zone 6">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.88333333333333"/>
+ <parameter value="lat_2=32.78333333333333"/>
+ <parameter value="lat_0=32.16666666666666"/>
+ <parameter value="lon_0=-116.25"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2772" name="NAD83(HARN) / Colorado North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.78333333333333"/>
+ <parameter value="lat_2=39.71666666666667"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2773" name="NAD83(HARN) / Colorado Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.75"/>
+ <parameter value="lat_2=38.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2774" name="NAD83(HARN) / Colorado South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.23333333333333"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2775" name="NAD83(HARN) / Connecticut">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.86666666666667"/>
+ <parameter value="lat_2=41.2"/>
+ <parameter value="lat_0=40.83333333333334"/>
+ <parameter value="lon_0=-72.75"/>
+ <parameter value="x_0=304800.6096"/>
+ <parameter value="y_0=152400.3048"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2776" name="NAD83(HARN) / Delaware">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-75.41666666666667"/>
+ <parameter value="k=0.999995"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2777" name="NAD83(HARN) / Florida East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2778" name="NAD83(HARN) / Florida West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-82"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2779" name="NAD83(HARN) / Florida North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.75"/>
+ <parameter value="lat_2=29.58333333333333"/>
+ <parameter value="lat_0=29"/>
+ <parameter value="lon_0=-84.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2780" name="NAD83(HARN) / Georgia East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-82.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2781" name="NAD83(HARN) / Georgia West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-84.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2782" name="NAD83(HARN) / Hawaii zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=18.83333333333333"/>
+ <parameter value="lon_0=-155.5"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2783" name="NAD83(HARN) / Hawaii zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=20.33333333333333"/>
+ <parameter value="lon_0=-156.6666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2784" name="NAD83(HARN) / Hawaii zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.16666666666667"/>
+ <parameter value="lon_0=-158"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2785" name="NAD83(HARN) / Hawaii zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.83333333333333"/>
+ <parameter value="lon_0=-159.5"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2786" name="NAD83(HARN) / Hawaii zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.66666666666667"/>
+ <parameter value="lon_0=-160.1666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2787" name="NAD83(HARN) / Idaho East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-112.1666666666667"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2788" name="NAD83(HARN) / Idaho Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-114"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2789" name="NAD83(HARN) / Idaho West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-115.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2790" name="NAD83(HARN) / Illinois East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-88.33333333333333"/>
+ <parameter value="k=0.999975"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2791" name="NAD83(HARN) / Illinois West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-90.16666666666667"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2792" name="NAD83(HARN) / Indiana East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-85.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=100000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2793" name="NAD83(HARN) / Indiana West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-87.08333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2794" name="NAD83(HARN) / Iowa North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.26666666666667"/>
+ <parameter value="lat_2=42.06666666666667"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2795" name="NAD83(HARN) / Iowa South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.61666666666667"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2796" name="NAD83(HARN) / Kansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.78333333333333"/>
+ <parameter value="lat_2=38.71666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2797" name="NAD83(HARN) / Kansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.56666666666667"/>
+ <parameter value="lat_2=37.26666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2798" name="NAD83(HARN) / Kentucky North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=38.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2799" name="NAD83(HARN) / Kentucky South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.93333333333333"/>
+ <parameter value="lat_2=36.73333333333333"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2800" name="NAD83(HARN) / Louisiana North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.66666666666666"/>
+ <parameter value="lat_2=31.16666666666667"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2801" name="NAD83(HARN) / Louisiana South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.7"/>
+ <parameter value="lat_2=29.3"/>
+ <parameter value="lat_0=28.5"/>
+ <parameter value="lon_0=-91.33333333333333"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2802" name="NAD83(HARN) / Maine East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2803" name="NAD83(HARN) / Maine West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.83333333333334"/>
+ <parameter value="lon_0=-70.16666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2804" name="NAD83(HARN) / Maryland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.45"/>
+ <parameter value="lat_2=38.3"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2805" name="NAD83(HARN) / Massachusetts Mainland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.68333333333333"/>
+ <parameter value="lat_2=41.71666666666667"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=750000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2806" name="NAD83(HARN) / Massachusetts Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.48333333333333"/>
+ <parameter value="lat_2=41.28333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2807" name="NAD83(HARN) / Michigan North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.08333333333334"/>
+ <parameter value="lat_2=45.48333333333333"/>
+ <parameter value="lat_0=44.78333333333333"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="x_0=8000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2808" name="NAD83(HARN) / Michigan Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.7"/>
+ <parameter value="lat_2=44.18333333333333"/>
+ <parameter value="lat_0=43.31666666666667"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=6000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2809" name="NAD83(HARN) / Michigan South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.66666666666666"/>
+ <parameter value="lat_2=42.1"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=4000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2810" name="NAD83(HARN) / Minnesota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.63333333333333"/>
+ <parameter value="lat_2=47.03333333333333"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-93.09999999999999"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2811" name="NAD83(HARN) / Minnesota Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.05"/>
+ <parameter value="lat_2=45.61666666666667"/>
+ <parameter value="lat_0=45"/>
+ <parameter value="lon_0=-94.25"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2812" name="NAD83(HARN) / Minnesota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.21666666666667"/>
+ <parameter value="lat_2=43.78333333333333"/>
+ <parameter value="lat_0=43"/>
+ <parameter value="lon_0=-94"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2813" name="NAD83(HARN) / Mississippi East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-88.83333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2814" name="NAD83(HARN) / Mississippi West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2815" name="NAD83(HARN) / Missouri East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-90.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=250000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2816" name="NAD83(HARN) / Missouri Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2817" name="NAD83(HARN) / Missouri West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.16666666666666"/>
+ <parameter value="lon_0=-94.5"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=850000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2818" name="NAD83(HARN) / Montana">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=45"/>
+ <parameter value="lat_0=44.25"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2819" name="NAD83(HARN) / Nebraska">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.83333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2820" name="NAD83(HARN) / Nevada East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-115.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=8000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2821" name="NAD83(HARN) / Nevada Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-116.6666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=6000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2822" name="NAD83(HARN) / Nevada West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-118.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=4000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2823" name="NAD83(HARN) / New Hampshire">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-71.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2824" name="NAD83(HARN) / New Jersey">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2825" name="NAD83(HARN) / New Mexico East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-104.3333333333333"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=165000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2826" name="NAD83(HARN) / New Mexico Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-106.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2827" name="NAD83(HARN) / New Mexico West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-107.8333333333333"/>
+ <parameter value="k=0.999917"/>
+ <parameter value="x_0=830000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2828" name="NAD83(HARN) / New York East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2829" name="NAD83(HARN) / New York Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-76.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=250000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2830" name="NAD83(HARN) / New York West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-78.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=350000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2831" name="NAD83(HARN) / New York Long Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.03333333333333"/>
+ <parameter value="lat_2=40.66666666666666"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-74"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2832" name="NAD83(HARN) / North Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.43333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2833" name="NAD83(HARN) / North Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.48333333333333"/>
+ <parameter value="lat_2=46.18333333333333"/>
+ <parameter value="lat_0=45.66666666666666"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2834" name="NAD83(HARN) / Ohio North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.7"/>
+ <parameter value="lat_2=40.43333333333333"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2835" name="NAD83(HARN) / Ohio South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.03333333333333"/>
+ <parameter value="lat_2=38.73333333333333"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2836" name="NAD83(HARN) / Oklahoma North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.76666666666667"/>
+ <parameter value="lat_2=35.56666666666667"/>
+ <parameter value="lat_0=35"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2837" name="NAD83(HARN) / Oklahoma South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.23333333333333"/>
+ <parameter value="lat_2=33.93333333333333"/>
+ <parameter value="lat_0=33.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2838" name="NAD83(HARN) / Oregon North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46"/>
+ <parameter value="lat_2=44.33333333333334"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2839" name="NAD83(HARN) / Oregon South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44"/>
+ <parameter value="lat_2=42.33333333333334"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2840" name="NAD83(HARN) / Rhode Island">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.08333333333334"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="k=0.999994"/>
+ <parameter value="x_0=100000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2841" name="NAD83(HARN) / South Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.68333333333333"/>
+ <parameter value="lat_2=44.41666666666666"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2842" name="NAD83(HARN) / South Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.4"/>
+ <parameter value="lat_2=42.83333333333334"/>
+ <parameter value="lat_0=42.33333333333334"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2843" name="NAD83(HARN) / Tennessee">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.41666666666666"/>
+ <parameter value="lat_2=35.25"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2844" name="NAD83(HARN) / Texas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.18333333333333"/>
+ <parameter value="lat_2=34.65"/>
+ <parameter value="lat_0=34"/>
+ <parameter value="lon_0=-101.5"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2845" name="NAD83(HARN) / Texas North Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.96666666666667"/>
+ <parameter value="lat_2=32.13333333333333"/>
+ <parameter value="lat_0=31.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2846" name="NAD83(HARN) / Texas Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=31.88333333333333"/>
+ <parameter value="lat_2=30.11666666666667"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2847" name="NAD83(HARN) / Texas South Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.28333333333333"/>
+ <parameter value="lat_2=28.38333333333333"/>
+ <parameter value="lat_0=27.83333333333333"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=4000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2848" name="NAD83(HARN) / Texas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=27.83333333333333"/>
+ <parameter value="lat_2=26.16666666666667"/>
+ <parameter value="lat_0=25.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=5000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2849" name="NAD83(HARN) / Utah North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.71666666666667"/>
+ <parameter value="lat_0=40.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2850" name="NAD83(HARN) / Utah Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.65"/>
+ <parameter value="lat_2=39.01666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2851" name="NAD83(HARN) / Utah South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.35"/>
+ <parameter value="lat_2=37.21666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2852" name="NAD83(HARN) / Vermont">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-72.5"/>
+ <parameter value="k=0.999964"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2853" name="NAD83(HARN) / Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.2"/>
+ <parameter value="lat_2=38.03333333333333"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2854" name="NAD83(HARN) / Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=36.76666666666667"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2855" name="NAD83(HARN) / Washington North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.5"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-120.8333333333333"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2856" name="NAD83(HARN) / Washington South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.33333333333334"/>
+ <parameter value="lat_2=45.83333333333334"/>
+ <parameter value="lat_0=45.33333333333334"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2857" name="NAD83(HARN) / West Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.25"/>
+ <parameter value="lat_2=39"/>
+ <parameter value="lat_0=38.5"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2858" name="NAD83(HARN) / West Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.88333333333333"/>
+ <parameter value="lat_2=37.48333333333333"/>
+ <parameter value="lat_0=37"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2859" name="NAD83(HARN) / Wisconsin North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.76666666666667"/>
+ <parameter value="lat_2=45.56666666666667"/>
+ <parameter value="lat_0=45.16666666666666"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2860" name="NAD83(HARN) / Wisconsin Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.5"/>
+ <parameter value="lat_2=44.25"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2861" name="NAD83(HARN) / Wisconsin South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.06666666666667"/>
+ <parameter value="lat_2=42.73333333333333"/>
+ <parameter value="lat_0=42"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2862" name="NAD83(HARN) / Wyoming East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-105.1666666666667"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2863" name="NAD83(HARN) / Wyoming East Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-107.3333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2864" name="NAD83(HARN) / Wyoming West Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-108.75"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2865" name="NAD83(HARN) / Wyoming West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-110.0833333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2866" name="NAD83(HARN) / Puerto Rico & Virgin Is.">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18.43333333333333"/>
+ <parameter value="lat_2=18.03333333333333"/>
+ <parameter value="lat_0=17.83333333333333"/>
+ <parameter value="lon_0=-66.43333333333334"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2867" name="NAD83(HARN) / Arizona East (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-110.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2868" name="NAD83(HARN) / Arizona Central (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-111.9166666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2869" name="NAD83(HARN) / Arizona West (ft)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-113.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2870" name="NAD83(HARN) / California zone 1 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.66666666666666"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2871" name="NAD83(HARN) / California zone 2 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.83333333333334"/>
+ <parameter value="lat_2=38.33333333333334"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2872" name="NAD83(HARN) / California zone 3 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.06666666666667"/>
+ <parameter value="lat_0=36.5"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2873" name="NAD83(HARN) / California zone 4 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.25"/>
+ <parameter value="lat_2=36"/>
+ <parameter value="lat_0=35.33333333333334"/>
+ <parameter value="lon_0=-119"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2874" name="NAD83(HARN) / California zone 5 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.46666666666667"/>
+ <parameter value="lat_2=34.03333333333333"/>
+ <parameter value="lat_0=33.5"/>
+ <parameter value="lon_0=-118"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2875" name="NAD83(HARN) / California zone 6 (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.88333333333333"/>
+ <parameter value="lat_2=32.78333333333333"/>
+ <parameter value="lat_0=32.16666666666666"/>
+ <parameter value="lon_0=-116.25"/>
+ <parameter value="x_0=2000000.0001016"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2876" name="NAD83(HARN) / Colorado North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.78333333333333"/>
+ <parameter value="lat_2=39.71666666666667"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2877" name="NAD83(HARN) / Colorado Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.75"/>
+ <parameter value="lat_2=38.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2878" name="NAD83(HARN) / Colorado South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.23333333333333"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=304800.6096012192"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2879" name="NAD83(HARN) / Connecticut (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.86666666666667"/>
+ <parameter value="lat_2=41.2"/>
+ <parameter value="lat_0=40.83333333333334"/>
+ <parameter value="lon_0=-72.75"/>
+ <parameter value="x_0=304800.6096012192"/>
+ <parameter value="y_0=152400.3048006096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2880" name="NAD83(HARN) / Delaware (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-75.41666666666667"/>
+ <parameter value="k=0.999995"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2881" name="NAD83(HARN) / Florida East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2882" name="NAD83(HARN) / Florida West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-82"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2883" name="NAD83(HARN) / Florida North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.75"/>
+ <parameter value="lat_2=29.58333333333333"/>
+ <parameter value="lat_0=29"/>
+ <parameter value="lon_0=-84.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2884" name="NAD83(HARN) / Georgia East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-82.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2885" name="NAD83(HARN) / Georgia West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-84.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2886" name="NAD83(HARN) / Idaho East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-112.1666666666667"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2887" name="NAD83(HARN) / Idaho Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-114"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2888" name="NAD83(HARN) / Idaho West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-115.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=800000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2889" name="NAD83(HARN) / Indiana East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-85.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=99999.99989839978"/>
+ <parameter value="y_0=249364.9987299975"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2890" name="NAD83(HARN) / Indiana West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-87.08333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=249364.9987299975"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2891" name="NAD83(HARN) / Kentucky North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=38.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2892" name="NAD83(HARN) / Kentucky South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.93333333333333"/>
+ <parameter value="lat_2=36.73333333333333"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=500000.0001016001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2893" name="NAD83(HARN) / Maryland (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.45"/>
+ <parameter value="lat_2=38.3"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="x_0=399999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2894" name="NAD83(HARN) / Massachusetts Mainland (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.68333333333333"/>
+ <parameter value="lat_2=41.71666666666667"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=750000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2895" name="NAD83(HARN) / Massachusetts Island (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.48333333333333"/>
+ <parameter value="lat_2=41.28333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2896" name="NAD83(HARN) / Michigan North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.08333333333334"/>
+ <parameter value="lat_2=45.48333333333333"/>
+ <parameter value="lat_0=44.78333333333333"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="x_0=7999999.999968001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2897" name="NAD83(HARN) / Michigan Central (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.7"/>
+ <parameter value="lat_2=44.18333333333333"/>
+ <parameter value="lat_0=43.31666666666667"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=5999999.999976001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2898" name="NAD83(HARN) / Michigan South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.66666666666666"/>
+ <parameter value="lat_2=42.1"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=3999999.999984"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2899" name="NAD83(HARN) / Mississippi East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-88.83333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2900" name="NAD83(HARN) / Mississippi West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2901" name="NAD83(HARN) / Montana (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=45"/>
+ <parameter value="lat_0=44.25"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2902" name="NAD83(HARN) / New Mexico East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-104.3333333333333"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=165000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2903" name="NAD83(HARN) / New Mexico Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-106.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2904" name="NAD83(HARN) / New Mexico West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-107.8333333333333"/>
+ <parameter value="k=0.999917"/>
+ <parameter value="x_0=830000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2905" name="NAD83(HARN) / New York East (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2906" name="NAD83(HARN) / New York Central (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-76.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=249999.9998983998"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2907" name="NAD83(HARN) / New York West (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-78.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=350000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2908" name="NAD83(HARN) / New York Long Island (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.03333333333333"/>
+ <parameter value="lat_2=40.66666666666666"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-74"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2909" name="NAD83(HARN) / North Dakota North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.43333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2910" name="NAD83(HARN) / North Dakota South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.48333333333333"/>
+ <parameter value="lat_2=46.18333333333333"/>
+ <parameter value="lat_0=45.66666666666666"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=599999.9999976"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2911" name="NAD83(HARN) / Oklahoma North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.76666666666667"/>
+ <parameter value="lat_2=35.56666666666667"/>
+ <parameter value="lat_0=35"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2912" name="NAD83(HARN) / Oklahoma South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.23333333333333"/>
+ <parameter value="lat_2=33.93333333333333"/>
+ <parameter value="lat_0=33.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2913" name="NAD83(HARN) / Oregon North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46"/>
+ <parameter value="lat_2=44.33333333333334"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2500000.0001424"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2914" name="NAD83(HARN) / Oregon South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44"/>
+ <parameter value="lat_2=42.33333333333334"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=1500000.0001464"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2915" name="NAD83(HARN) / Tennessee (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.41666666666666"/>
+ <parameter value="lat_2=35.25"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2916" name="NAD83(HARN) / Texas North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.18333333333333"/>
+ <parameter value="lat_2=34.65"/>
+ <parameter value="lat_0=34"/>
+ <parameter value="lon_0=-101.5"/>
+ <parameter value="x_0=200000.0001016002"/>
+ <parameter value="y_0=999999.9998983998"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2917" name="NAD83(HARN) / Texas North Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.96666666666667"/>
+ <parameter value="lat_2=32.13333333333333"/>
+ <parameter value="lat_0=31.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2918" name="NAD83(HARN) / Texas Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=31.88333333333333"/>
+ <parameter value="lat_2=30.11666666666667"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=699999.9998983998"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2919" name="NAD83(HARN) / Texas South Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.28333333333333"/>
+ <parameter value="lat_2=28.38333333333333"/>
+ <parameter value="lat_0=27.83333333333333"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=3999999.9998984"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2920" name="NAD83(HARN) / Texas South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=27.83333333333333"/>
+ <parameter value="lat_2=26.16666666666667"/>
+ <parameter value="lat_0=25.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=300000.0000000001"/>
+ <parameter value="y_0=5000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2921" name="NAD83(HARN) / Utah North (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.71666666666667"/>
+ <parameter value="lat_0=40.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=999999.9999960001"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2922" name="NAD83(HARN) / Utah Central (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.65"/>
+ <parameter value="lat_2=39.01666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=1999999.999992"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2923" name="NAD83(HARN) / Utah South (ft)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.35"/>
+ <parameter value="lat_2=37.21666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000.0001504"/>
+ <parameter value="y_0=2999999.999988"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2924" name="NAD83(HARN) / Virginia North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.2"/>
+ <parameter value="lat_2=38.03333333333333"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000.0001016"/>
+ <parameter value="y_0=2000000.0001016"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2925" name="NAD83(HARN) / Virginia South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=36.76666666666667"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000.0001016"/>
+ <parameter value="y_0=999999.9998983998"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2926" name="NAD83(HARN) / Washington North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.5"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-120.8333333333333"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2927" name="NAD83(HARN) / Washington South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.33333333333334"/>
+ <parameter value="lat_2=45.83333333333334"/>
+ <parameter value="lat_0=45.33333333333334"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=500000.0001016001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2928" name="NAD83(HARN) / Wisconsin North (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.76666666666667"/>
+ <parameter value="lat_2=45.56666666666667"/>
+ <parameter value="lat_0=45.16666666666666"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2929" name="NAD83(HARN) / Wisconsin Central (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.5"/>
+ <parameter value="lat_2=44.25"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2930" name="NAD83(HARN) / Wisconsin South (ftUS)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.06666666666667"/>
+ <parameter value="lat_2=42.73333333333333"/>
+ <parameter value="lat_0=42"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2931" name="Beduaram / TM 13 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.0000000001"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2932" name="QND95 / Qatar National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.45"/>
+ <parameter value="lon_0=51.21666666666667"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-119.425,-303.659,-11.0006,1.1643,0.174458,1.09626,3.65706"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2933" name="Segara / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-404.78,685.68,45.47,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2934" name="Segara (Jakarta) / NEIEZ">
+ <parameter value="proj=merc"/>
+ <parameter value="lat_ts=0"/>
+ <parameter value="lon_0=216.8077194444444"/>
+ <parameter value="k=0.997000"/>
+ <parameter value="x_0=3900000"/>
+ <parameter value="y_0=900000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2935" name="Pulkovo 1942 / CS63 zone A1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1166666666666667"/>
+ <parameter value="lon_0=41.53333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2936" name="Pulkovo 1942 / CS63 zone A2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1166666666666667"/>
+ <parameter value="lon_0=44.53333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2937" name="Pulkovo 1942 / CS63 zone A3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1166666666666667"/>
+ <parameter value="lon_0=47.53333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2938" name="Pulkovo 1942 / CS63 zone A4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1166666666666667"/>
+ <parameter value="lon_0=50.53333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2939" name="Pulkovo 1942 / CS63 zone K2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1333333333333333"/>
+ <parameter value="lon_0=50.76666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2940" name="Pulkovo 1942 / CS63 zone K3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1333333333333333"/>
+ <parameter value="lon_0=53.76666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2941" name="Pulkovo 1942 / CS63 zone K4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.1333333333333333"/>
+ <parameter value="lon_0=56.76666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2942" name="Porto Santo / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2943" name="Selvagem Grande / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2944" name="NAD83(CSRS) / SCoPQ zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2945" name="NAD83(CSRS) / MTM zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-58.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2946" name="NAD83(CSRS) / MTM zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2947" name="NAD83(CSRS) / MTM zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2948" name="NAD83(CSRS) / MTM zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-67.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2949" name="NAD83(CSRS) / MTM zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2950" name="NAD83(CSRS) / MTM zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-73.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2951" name="NAD83(CSRS) / MTM zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-76.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2952" name="NAD83(CSRS) / MTM zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2953" name="NAD83(CSRS) / New Brunswick Stereo">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-66.5"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=7500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2954" name="NAD83(CSRS) / Prince Edward Isl. Stereographic (NAD83)">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=47.25"/>
+ <parameter value="lon_0=-63"/>
+ <parameter value="k=0.999912"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2955" name="NAD83(CSRS) / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2956" name="NAD83(CSRS) / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2957" name="NAD83(CSRS) / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2958" name="NAD83(CSRS) / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2959" name="NAD83(CSRS) / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2960" name="NAD83(CSRS) / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2961" name="NAD83(CSRS) / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="2962" name="NAD83(CSRS) / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3036" name="Moznet / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,-0,-0,-0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3037" name="Moznet / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,-0,-0,-0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3148" name="Indian 1960 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3149" name="Indian 1960 / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3176" name="Indian 1960 / TM 106 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=106"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3200" name="FD58 / Iraq zone">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.5"/>
+ <parameter value="lat_0=32.5"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k_0=0.9987864078000001"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=1166200"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3300" name="Estonian Coordinate System of 1992">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=59.33333333333334"/>
+ <parameter value="lat_2=58"/>
+ <parameter value="lat_0=57.51755393055556"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=6375000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0.055,-0.541,-0.185,0.0183,-0.0003,-0.007,-0.014"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3301" name="Estonian Coordinate System of 1997">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=59.33333333333334"/>
+ <parameter value="lat_2=58"/>
+ <parameter value="lat_0=57.51755393055556"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=6375000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3439" name="PSD93 / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3440" name="PSD93 / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3561" name="Old Hawaiian / Hawaii zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=18.83333333333333"/>
+ <parameter value="lon_0=-155.5"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3562" name="Old Hawaiian / Hawaii zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=20.33333333333333"/>
+ <parameter value="lon_0=-156.6666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3563" name="Old Hawaiian / Hawaii zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.16666666666667"/>
+ <parameter value="lon_0=-158"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3564" name="Old Hawaiian / Hawaii zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.83333333333333"/>
+ <parameter value="lon_0=-159.5"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3565" name="Old Hawaiian / Hawaii zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.66666666666667"/>
+ <parameter value="lon_0=-160.1666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3920" name="Puerto Rico / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3991" name="Puerto Rico State Plane CS of 1927">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18.43333333333333"/>
+ <parameter value="lat_2=18.03333333333333"/>
+ <parameter value="lat_0=17.83333333333333"/>
+ <parameter value="lon_0=-66.43333333333334"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="3992" name="Puerto Rico / St. Croix">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18.43333333333333"/>
+ <parameter value="lat_2=18.03333333333333"/>
+ <parameter value="lat_0=17.83333333333333"/>
+ <parameter value="lon_0=-66.43333333333334"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=30480.06096012192"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4001" name="Unknown datum based upon the Airy 1830 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4002" name="Unknown datum based upon the Airy Modified 1849 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4003" name="Unknown datum based upon the Australian National Spheroid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4004" name="Unknown datum based upon the Bessel 1841 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4005" name="Unknown datum based upon the Bessel Modified ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4006" name="Unknown datum based upon the Bessel Namibia ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bess_nam"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4007" name="Unknown datum based upon the Clarke 1858 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4008" name="Unknown datum based upon the Clarke 1866 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4009" name="Unknown datum based upon the Clarke 1866 Michigan ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4010" name="Unknown datum based upon the Clarke 1880 (Benoit) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378300.789"/>
+ <parameter value="b=6356566.435"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4011" name="Unknown datum based upon the Clarke 1880 (IGN) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4012" name="Unknown datum based upon the Clarke 1880 (RGS) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4013" name="Unknown datum based upon the Clarke 1880 (Arc) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4014" name="Unknown datum based upon the Clarke 1880 (SGA 1922) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356514.996941779"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4015" name="Unknown datum based upon the Everest 1830 (1937 Adjustment) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4016" name="Unknown datum based upon the Everest 1830 (1967 Definition) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4018" name="Unknown datum based upon the Everest 1830 Modified ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4019" name="Unknown datum based upon the GRS 1980 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4020" name="Unknown datum based upon the Helmert 1906 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4021" name="Unknown datum based upon the Indonesian National Spheroid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4022" name="Unknown datum based upon the International 1924 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4024" name="Unknown datum based upon the Krassowsky 1940 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4025" name="Unknown datum based upon the NWL 9D ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4027" name="Unknown datum based upon the Plessis 1817 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6376523"/>
+ <parameter value="b=6355862.933255573"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4028" name="Unknown datum based upon the Struve 1860 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378298.3"/>
+ <parameter value="b=6356657.142669562"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4029" name="Unknown datum based upon the War Office ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4030" name="Unknown datum based upon the WGS 84 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4031" name="Unknown datum based upon the GEM 10C ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4032" name="Unknown datum based upon the OSU86F ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378136.2"/>
+ <parameter value="b=6356751.516927429"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4033" name="Unknown datum based upon the OSU91A ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378136.3"/>
+ <parameter value="b=6356751.616592146"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4034" name="Unknown datum based upon the Clarke 1880 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4035" name="Unknown datum based upon the Authalic Sphere">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6371000"/>
+ <parameter value="b=6371000"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4036" name="Unknown datum based upon the GRS 1967 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4041" name="Unknown datum based upon the Average Terrestrial System 1977 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4042" name="Unknown datum based upon the Everest (1830 Definition) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4043" name="Unknown datum based upon the WGS 72 ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4044" name="Unknown datum based upon the Everest 1830 (1962 Definition) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4045" name="Unknown datum based upon the Everest 1830 (1975 Definition) ellipsoid">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4047" name="Unspecified based upon the GRS 1980 Authalic Sphere">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6370997"/>
+ <parameter value="b=6370997"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4120" name="Greek">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4121" name="GGRS87">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=-199.87,74.79,246.62,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4122" name="ATS77">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378135"/>
+ <parameter value="b=6356750.304921594"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4123" name="KKJ">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4124" name="RT90">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4125" name="Samboja">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-404.78,685.68,45.47,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4126" name="LKS94 (ETRS89)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4127" name="Tete">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4128" name="Madzansua">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4129" name="Observatario">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4130" name="Moznet">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,-0,-0,-0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4131" name="Indian 1960">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4132" name="FD58">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4133" name="EST92">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0.055,-0.541,-0.185,0.0183,-0.0003,-0.007,-0.014"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4134" name="PDO Survey Datum 1993">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4135" name="Old Hawaiian">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4136" name="St. Lawrence Island">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4137" name="St. Paul Island">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4138" name="St. George Island">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4139" name="Puerto Rico">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4140" name="NAD83(CSRS98)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4141" name="Israel">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4142" name="Locodjo 1965">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-125,53,467,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4143" name="Abidjan 1987">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-124.76,53,466.79,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4144" name="Kalianpur 1937">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4145" name="Kalianpur 1962">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4146" name="Kalianpur 1975">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4147" name="Hanoi 1972">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-17.51,-108.32,-62.39,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4148" name="Hartebeesthoek94">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4149" name="CH1903">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4150" name="CH1903+">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=674.374,15.056,405.346,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4151" name="CHTRF95">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4152" name="NAD83(HARN)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4153" name="Rassadiran">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-133.63,-157.5,-158.62,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4154" name="ED50(ED77)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4155" name="Dabola 1981">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-83,37,124,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4156" name="S-JTSK">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4157" name="Mount Dillon">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4158" name="Naparima 1955">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4159" name="ELD79">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4160" name="Chos Malal 1914">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4161" name="Pampa del Castillo">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4162" name="Korean 1985">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4163" name="Yemen NGN96">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4164" name="South Yemen">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-76,-138,67,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4165" name="Bissau">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-173,253,27,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4166" name="Korean 1995">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4167" name="NZGD2000">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4168" name="Accra">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="towgs84=-199,32,322,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4169" name="American Samoa 1962">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="towgs84=-115,118,426,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4170" name="SIRGAS">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4171" name="RGF93">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4172" name="POSGAR">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4173" name="IRENET95">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4174" name="Sierra Leone 1924">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378300"/>
+ <parameter value="b=6356751.689189189"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4175" name="Sierra Leone 1968">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-88,4,101,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4176" name="Australian Antarctic">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4178" name="Pulkovo 1942(83)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4179" name="Pulkovo 1942(58)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4180" name="EST97">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4181" name="Luxembourg 1930">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-193,13.7,-39.3,-0.41,-2.933,2.688,0.43"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4182" name="Azores Occidental 1939">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4183" name="Azores Central 1948">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4184" name="Azores Oriental 1940">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4185" name="Madeira 1936">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4188" name="OSNI 1952">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4189" name="REGVEN">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4190" name="POSGAR 98">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4191" name="Albanian 1987">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4192" name="Douala 1948">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4193" name="Manoca 1962">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-70.9,-151.8,-41.4,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4194" name="Qornoq 1927">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4195" name="Scoresbysund 1952">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=105,326,-102.5,0,0,0.814,-0.6"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4196" name="Ammassalik 1958">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-45,417,-3.5,0,0,0.814,-0.6"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4197" name="Garoua">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4198" name="Kousseri">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4199" name="Egypt 1930">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4200" name="Pulkovo 1995">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4201" name="Adindan">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4202" name="AGD66">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4203" name="AGD84">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4204" name="Ain el Abd">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4205" name="Afgooye">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-43,-163,45,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4206" name="Agadez">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4207" name="Lisbon">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4208" name="Aratu">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4209" name="Arc 1950">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4210" name="Arc 1960">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4211" name="Batavia">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4212" name="Barbados 1938">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4213" name="Beduaram">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4214" name="Beijing 1954">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4215" name="Belge 1950">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4216" name="Bermuda 1957">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="towgs84=-73,213,296,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4218" name="Bogota 1975">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4219" name="Bukit Rimpah">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-384,664,-48,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4220" name="Camacupa">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4221" name="Campo Inchauspe">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4222" name="Cape">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4223" name="Carthage">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4224" name="Chua">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-134,229,-29,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4225" name="Corrego Alegre">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-206,172,-6,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4226" name="Cote d'Ivoire">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4227" name="Deir ez Zor">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4228" name="Douala">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4229" name="Egypt 1907">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4230" name="ED50">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4231" name="ED87">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-82.981,-99.719,-110.709,-0.5076,0.1503,0.3898,-0.3143"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4232" name="Fahud">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4233" name="Gandajika 1970">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4234" name="Garoua">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4235" name="Guyane Francaise">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4236" name="Hu Tzu Shan">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-637,-549,-203,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4237" name="HD72">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4238" name="ID74">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4239" name="Indian 1954">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="towgs84=217,823,299,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4240" name="Indian 1975">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4241" name="Jamaica 1875">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4242" name="JAD69">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4243" name="Kalianpur 1880">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4244" name="Kandawala">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="towgs84=-97,787,86,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4245" name="Kertau">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="towgs84=-11,851,5,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4246" name="KOC">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4247" name="La Canoa">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-273.5,110.6,-357.9,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4248" name="PSAD56">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4249" name="Lake">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4250" name="Leigon">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-130,29,364,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4251" name="Liberia 1964">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-90,40,88,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4252" name="Lome">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4253" name="Luzon 1911">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4254" name="Hito XVIII 1963">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4255" name="Herat North">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-333,-222,114,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4256" name="Mahe 1971">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=41,-220,-134,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4257" name="Makassar">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-587.8,519.75,145.76,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4258" name="ETRS89">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4259" name="Malongo 1987">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4260" name="Manoca">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-70.9,-151.8,-41.4,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4261" name="Merchich">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=31,146,47,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4262" name="Massawa">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=639,405,60,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4263" name="Minna">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4264" name="Mhast">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-252.95,-4.11,-96.38,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4265" name="Monte Mario">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4266" name="M'poraloko">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4267" name="NAD27">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4268" name="NAD27 Michigan">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4269" name="NAD83">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4270" name="Nahrwan 1967">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4271" name="Naparima 1972">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4272" name="NZGD49">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4273" name="NGO 1948">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4274" name="Datum 73">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4275" name="NTF">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4276" name="NSWC 9Z-2">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4277" name="OSGB 1936">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4278" name="OSGB70">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4279" name="OS(SN)80">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4280" name="Padang">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4281" name="Palestine 1923">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378300.789"/>
+ <parameter value="b=6356566.435"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4282" name="Pointe Noire">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4283" name="GDA94">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4284" name="Pulkovo 1942">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4285" name="Qatar 1974">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4286" name="Qatar 1948">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4287" name="Qornoq">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=164,138,-189,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4288" name="Loma Quintana">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4289" name="Amersfoort">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4291" name="SAD69">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4292" name="Sapper Hill 1943">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-355,21,72,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4293" name="Schwarzeck">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bess_nam"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4294" name="Segora">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4295" name="Serindung">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4296" name="Sudan">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4297" name="Tananarive">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-189,-242,-91,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4298" name="Timbalai 1948">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4299" name="TM65">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4300" name="TM75">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4301" name="Tokyo">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4302" name="Trinidad 1903">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="towgs84=-61.702,284.488,472.052,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4303" name="TC(1948)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4304" name="Voirol 1875">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-73,-247,227,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4306" name="Bern 1938">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4307" name="Nord Sahara 1959">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4308" name="RT38">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4309" name="Yacare">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-155,171,37,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4310" name="Yoff">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4311" name="Zanderij">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-265,120,-358,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4312" name="MGI">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4313" name="Belge 1972">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4314" name="DHDN">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4315" name="Conakry 1905">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-23,259,-9,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4316" name="Dealul Piscului 1933">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=103.25,-100.4,-307.19,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4317" name="Dealul Piscului 1970">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4318" name="NGN">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4319" name="KUDAMS">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4322" name="WGS 72">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4324" name="WGS 72BE">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4326" name="WGS 84">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4600" name="Anguilla 1957">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4601" name="Antigua 1943">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-255,-15,71,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4602" name="Dominica 1945">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=725,685,536,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4603" name="Grenada 1953">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=72,213.7,93,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4604" name="Montserrat 1958">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=174,359,365,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4605" name="St. Kitts 1955">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=9,183,236,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4606" name="St. Lucia 1955">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-149,128,296,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4607" name="St. Vincent 1945">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4608" name="NAD27(76)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4609" name="NAD27(CGQ77)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4610" name="Xian 1980">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378140"/>
+ <parameter value="b=6356755.288157528"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4611" name="Hong Kong 1980">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-162.619,-276.959,-161.764,0.067753,-2.24365,-1.15883,-1.09425"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4612" name="JGD2000">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4613" name="Segara">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-404.78,685.68,45.47,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4614" name="QND95">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-119.425,-303.659,-11.0006,1.1643,0.174458,1.09626,3.65706"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4615" name="Porto Santo">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4616" name="Selvagem Grande">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4617" name="NAD83(CSRS)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4801" name="Bern 1898 (Bern)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=bern"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4802" name="Bogota 1975 (Bogota)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=bogota"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4803" name="Lisbon (Lisbon)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=lisbon"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4804" name="Makassar (Jakarta)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-587.8,519.75,145.76,0,0,0,0"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4805" name="MGI (Ferro)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4806" name="Monte Mario (Rome)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=rome"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4807" name="NTF (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4808" name="Padang (Jakarta)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4809" name="Belge 1950 (Brussels)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=brussels"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4810" name="Tananarive (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-189,-242,-91,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4811" name="Voirol 1875 (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-73,-247,227,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4813" name="Batavia (Jakarta)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4814" name="RT38 (Stockholm)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=stockholm"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4815" name="Greek (Athens)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=athens"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4816" name="Carthage (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4817" name="NGO 1948 (Oslo)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4818" name="S-JTSK (Ferro)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4819" name="Nord Sahara 1959 (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4820" name="Segara (Jakarta)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4901" name="ATF (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6376523"/>
+ <parameter value="b=6355862.933255573"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4902" name="NDG (Paris)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6376523"/>
+ <parameter value="b=6355862.933255573"/>
+ <parameter value="pm=paris"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4903" name="Madrid 1870 (Madrid)">
+ <parameter value="proj=longlat"/>
+ <parameter value="a=6378298.3"/>
+ <parameter value="b=6356657.142669562"/>
+ <parameter value="pm=madrid"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="4904" name="Lisbon 1890 (Lisbon)">
+ <parameter value="proj=longlat"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=lisbon"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20004" name="Pulkovo 1995 / Gauss-Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20005" name="Pulkovo 1995 / Gauss-Kruger zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20006" name="Pulkovo 1995 / Gauss-Kruger zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20007" name="Pulkovo 1995 / Gauss-Kruger zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20008" name="Pulkovo 1995 / Gauss-Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20009" name="Pulkovo 1995 / Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20010" name="Pulkovo 1995 / Gauss-Kruger zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=10500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20011" name="Pulkovo 1995 / Gauss-Kruger zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=11500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20012" name="Pulkovo 1995 / Gauss-Kruger zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=12500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20013" name="Pulkovo 1995 / Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20014" name="Pulkovo 1995 / Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20015" name="Pulkovo 1995 / Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20016" name="Pulkovo 1995 / Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20017" name="Pulkovo 1995 / Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20018" name="Pulkovo 1995 / Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20019" name="Pulkovo 1995 / Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20020" name="Pulkovo 1995 / Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20021" name="Pulkovo 1995 / Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20022" name="Pulkovo 1995 / Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20023" name="Pulkovo 1995 / Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20024" name="Pulkovo 1995 / Gauss-Kruger zone 24">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=24500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20025" name="Pulkovo 1995 / Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20026" name="Pulkovo 1995 / Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20027" name="Pulkovo 1995 / Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20028" name="Pulkovo 1995 / Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20029" name="Pulkovo 1995 / Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20030" name="Pulkovo 1995 / Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20031" name="Pulkovo 1995 / Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20032" name="Pulkovo 1995 / Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20064" name="Pulkovo 1995 / Gauss-Kruger 4N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20065" name="Pulkovo 1995 / Gauss-Kruger 5N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20066" name="Pulkovo 1995 / Gauss-Kruger 6N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20067" name="Pulkovo 1995 / Gauss-Kruger 7N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20068" name="Pulkovo 1995 / Gauss-Kruger 8N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20069" name="Pulkovo 1995 / Gauss-Kruger 9N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20070" name="Pulkovo 1995 / Gauss-Kruger 10N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20071" name="Pulkovo 1995 / Gauss-Kruger 11N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20072" name="Pulkovo 1995 / Gauss-Kruger 12N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20073" name="Pulkovo 1995 / Gauss-Kruger 13N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20074" name="Pulkovo 1995 / Gauss-Kruger 14N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20075" name="Pulkovo 1995 / Gauss-Kruger 15N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20076" name="Pulkovo 1995 / Gauss-Kruger 16N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20077" name="Pulkovo 1995 / Gauss-Kruger 17N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20078" name="Pulkovo 1995 / Gauss-Kruger 18N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20079" name="Pulkovo 1995 / Gauss-Kruger 19N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20080" name="Pulkovo 1995 / Gauss-Kruger 20N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20081" name="Pulkovo 1995 / Gauss-Kruger 21N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20082" name="Pulkovo 1995 / Gauss-Kruger 22N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20083" name="Pulkovo 1995 / Gauss-Kruger 23N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20084" name="Pulkovo 1995 / Gauss-Kruger 24N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20085" name="Pulkovo 1995 / Gauss-Kruger 25N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20086" name="Pulkovo 1995 / Gauss-Kruger 26N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20087" name="Pulkovo 1995 / Gauss-Kruger 27N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20088" name="Pulkovo 1995 / Gauss-Kruger 28N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20089" name="Pulkovo 1995 / Gauss-Kruger 29N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20090" name="Pulkovo 1995 / Gauss-Kruger 30N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20091" name="Pulkovo 1995 / Gauss-Kruger 31N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20092" name="Pulkovo 1995 / Gauss-Kruger 32N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20137" name="Adindan / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20138" name="Adindan / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20248" name="AGD66 / AMG zone 48">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20249" name="AGD66 / AMG zone 49">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20250" name="AGD66 / AMG zone 50">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20251" name="AGD66 / AMG zone 51">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20252" name="AGD66 / AMG zone 52">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20253" name="AGD66 / AMG zone 53">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20254" name="AGD66 / AMG zone 54">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20255" name="AGD66 / AMG zone 55">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20256" name="AGD66 / AMG zone 56">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20257" name="AGD66 / AMG zone 57">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20258" name="AGD66 / AMG zone 58">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20348" name="AGD84 / AMG zone 48">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20349" name="AGD84 / AMG zone 49">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20350" name="AGD84 / AMG zone 50">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20351" name="AGD84 / AMG zone 51">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20352" name="AGD84 / AMG zone 52">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20353" name="AGD84 / AMG zone 53">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20354" name="AGD84 / AMG zone 54">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20355" name="AGD84 / AMG zone 55">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20356" name="AGD84 / AMG zone 56">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20357" name="AGD84 / AMG zone 57">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20358" name="AGD84 / AMG zone 58">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=aust_SA"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20437" name="Ain el Abd / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20438" name="Ain el Abd / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20439" name="Ain el Abd / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20499" name="Ain el Abd / Bahrain Grid">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20538" name="Afgooye / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-43,-163,45,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20539" name="Afgooye / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="towgs84=-43,-163,45,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20790" name="Lisbon (Lisbon)/Portuguese National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-8.131906111111112"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=lisbon"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20791" name="Lisbon (Lisbon)/Portuguese Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-8.131906111111112"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=lisbon"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20822" name="Aratu / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20823" name="Aratu / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20824" name="Aratu / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20934" name="Arc 1950 / UTM zone 34S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20935" name="Arc 1950 / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="20936" name="Arc 1950 / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21035" name="Arc 1960 / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21036" name="Arc 1960 / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21037" name="Arc 1960 / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21095" name="Arc 1960 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21096" name="Arc 1960 / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21097" name="Arc 1960 / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21100" name="Batavia (Jakarta) / NEIEZ">
+ <parameter value="proj=merc"/>
+ <parameter value="lat_ts=0"/>
+ <parameter value="lon_0=216.8077194444444"/>
+ <parameter value="k=0.997000"/>
+ <parameter value="x_0=3900000"/>
+ <parameter value="y_0=900000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21148" name="Batavia / UTM zone 48S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21149" name="Batavia / UTM zone 49S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21150" name="Batavia / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21291" name="Barbados 1938 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-62"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21292" name="Barbados 1938 / Barbados National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=13.17638888888889"/>
+ <parameter value="lon_0=-59.55972222222222"/>
+ <parameter value="k=0.999999"/>
+ <parameter value="x_0=30000"/>
+ <parameter value="y_0=75000"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21413" name="Beijing 1954 / Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21414" name="Beijing 1954 / Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21415" name="Beijing 1954 / Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21416" name="Beijing 1954 / Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21417" name="Beijing 1954 / Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21418" name="Beijing 1954 / Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21419" name="Beijing 1954 / Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21420" name="Beijing 1954 / Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21421" name="Beijing 1954 / Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21422" name="Beijing 1954 / Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21423" name="Beijing 1954 / Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21453" name="Beijing 1954 / Gauss-Kruger CM 75E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21454" name="Beijing 1954 / Gauss-Kruger CM 81E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21455" name="Beijing 1954 / Gauss-Kruger CM 87E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21456" name="Beijing 1954 / Gauss-Kruger CM 93E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21457" name="Beijing 1954 / Gauss-Kruger CM 99E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21458" name="Beijing 1954 / Gauss-Kruger CM 105E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21459" name="Beijing 1954 / Gauss-Kruger CM 111E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21460" name="Beijing 1954 / Gauss-Kruger CM 117E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21461" name="Beijing 1954 / Gauss-Kruger CM 123E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21462" name="Beijing 1954 / Gauss-Kruger CM 129E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21463" name="Beijing 1954 / Gauss-Kruger CM 135E">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21473" name="Beijing 1954 / Gauss-Kruger 13N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21474" name="Beijing 1954 / Gauss-Kruger 14N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21475" name="Beijing 1954 / Gauss-Kruger 15N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21476" name="Beijing 1954 / Gauss-Kruger 16N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21477" name="Beijing 1954 / Gauss-Kruger 17N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21478" name="Beijing 1954 / Gauss-Kruger 18N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21479" name="Beijing 1954 / Gauss-Kruger 19N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21480" name="Beijing 1954 / Gauss-Kruger 20N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21481" name="Beijing 1954 / Gauss-Kruger 21N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21482" name="Beijing 1954 / Gauss-Kruger 22N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21483" name="Beijing 1954 / Gauss-Kruger 23N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21500" name="Belge 1950 (Brussels) / Belge Lambert 50">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.83333333333334"/>
+ <parameter value="lat_2=51.16666666666666"/>
+ <parameter value="lat_0=90"/>
+ <parameter value="lon_0=4.367975"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=5400000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=brussels"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21817" name="Bogota 1975 / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21818" name="Bogota 1975 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21891" name="Bogota 1975 / Colombia West zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.599047222222222"/>
+ <parameter value="lon_0=-77.08091666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21892" name="Bogota 1975 / Colombia Bogota zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.599047222222222"/>
+ <parameter value="lon_0=-74.08091666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21893" name="Bogota 1975 / Colombia East Central zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.599047222222222"/>
+ <parameter value="lon_0=-71.08091666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="21894" name="Bogota 1975 / Colombia East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.599047222222222"/>
+ <parameter value="lon_0=-68.08091666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22032" name="Camacupa / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22033" name="Camacupa / UTM zone 33S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="south"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22091" name="Camacupa / TM 11.30 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=11.5"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22092" name="Camacupa / TM 12 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22191" name="Campo Inchauspe / Argentina 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-72"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22192" name="Campo Inchauspe / Argentina 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22193" name="Campo Inchauspe / Argentina 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-66"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22194" name="Campo Inchauspe / Argentina 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22195" name="Campo Inchauspe / Argentina 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-60"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22196" name="Campo Inchauspe / Argentina 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22197" name="Campo Inchauspe / Argentina 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lon_0=-54"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22234" name="Cape / UTM zone 34S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22235" name="Cape / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22236" name="Cape / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.145"/>
+ <parameter value="b=6356514.966398753"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22332" name="Carthage / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22391" name="Carthage / Nord Tunisie">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=9.9"/>
+ <parameter value="k_0=0.999625544"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22392" name="Carthage / Sud Tunisie">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.3"/>
+ <parameter value="lat_0=33.3"/>
+ <parameter value="lon_0=9.9"/>
+ <parameter value="k_0=0.999625769"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22523" name="Corrego Alegre / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-206,172,-6,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22524" name="Corrego Alegre / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-206,172,-6,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22700" name="Deir ez Zor / Levant Zone">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.65"/>
+ <parameter value="lat_0=34.65"/>
+ <parameter value="lon_0=37.35"/>
+ <parameter value="k_0=0.9996256"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22770" name="Deir ez Zor / Syria Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.65"/>
+ <parameter value="lat_0=34.65"/>
+ <parameter value="lon_0=37.35"/>
+ <parameter value="k_0=0.9996256"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22780" name="Deir ez Zor / Levant Stereographic">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=34.2"/>
+ <parameter value="lon_0=39.15"/>
+ <parameter value="k=0.999534"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22832" name="Douala / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22991" name="Egypt 1907 / Blue Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=35"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=1100000"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22992" name="Egypt 1907 / Red Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=31"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=615000"/>
+ <parameter value="y_0=810000"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22993" name="Egypt 1907 / Purple Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="22994" name="Egypt 1907 / Extended Purple Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=1200000"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23028" name="ED50 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23029" name="ED50 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23030" name="ED50 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23031" name="ED50 / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23032" name="ED50 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23033" name="ED50 / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23034" name="ED50 / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23035" name="ED50 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23036" name="ED50 / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23037" name="ED50 / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23038" name="ED50 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23090" name="ED50 / TM 0 N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=0"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23095" name="ED50 / TM 5 NE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=5"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23239" name="Fahud / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23240" name="Fahud / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23433" name="Garoua / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23846" name="ID74 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23847" name="ID74 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23848" name="ID74 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23849" name="ID74 / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23850" name="ID74 / UTM zone 50N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23851" name="ID74 / UTM zone 51N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23852" name="ID74 / UTM zone 52N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23853" name="ID74 / UTM zone 53N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23886" name="ID74 / UTM zone 46S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23887" name="ID74 / UTM zone 47S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23888" name="ID74 / UTM zone 48S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23889" name="ID74 / UTM zone 49S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23890" name="ID74 / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23891" name="ID74 / UTM zone 51S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23892" name="ID74 / UTM zone 52S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23893" name="ID74 / UTM zone 53S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23894" name="ID74 / UTM zone 54S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="a=6378160"/>
+ <parameter value="b=6356774.50408554"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23946" name="Indian 1954 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="towgs84=217,823,299,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23947" name="Indian 1954 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="towgs84=217,823,299,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="23948" name="Indian 1954 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="towgs84=217,823,299,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24047" name="Indian 1975 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24048" name="Indian 1975 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24100" name="Jamaica 1875 / Jamaica (Old Grid)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18"/>
+ <parameter value="lat_0=18"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=167638.49575"/>
+ <parameter value="y_0=121918.906"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="to_meter=0.304797265"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24200" name="JAD69 / Jamaica National Grid">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18"/>
+ <parameter value="lat_0=18"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="k_0=1"/>
+ <parameter value="x_0=250000"/>
+ <parameter value="y_0=150000"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24305" name="Kalianpur 1937 / UTM zone 45N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24306" name="Kalianpur 1937 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24311" name="Kalianpur 1962 / UTM zone 41N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24312" name="Kalianpur 1962 / UTM zone 42N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24313" name="Kalianpur 1962 / UTM zone 43N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24342" name="Kalianpur 1975 / UTM zone 42N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24343" name="Kalianpur 1975 / UTM zone 43N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24344" name="Kalianpur 1975 / UTM zone 44N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24345" name="Kalianpur 1975 / UTM zone 45N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24346" name="Kalianpur 1975 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24347" name="Kalianpur 1975 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24370" name="Kalianpur 1880 / India zone 0">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.5"/>
+ <parameter value="lat_0=39.5"/>
+ <parameter value="lon_0=68"/>
+ <parameter value="k_0=0.99846154"/>
+ <parameter value="x_0=2153865.73916853"/>
+ <parameter value="y_0=2368292.194628102"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24371" name="Kalianpur 1880 / India zone I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.5"/>
+ <parameter value="lat_0=32.5"/>
+ <parameter value="lon_0=68"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.592233322"/>
+ <parameter value="y_0=914398.5307444407"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24372" name="Kalianpur 1880 / India zone IIa">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=74"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.592233322"/>
+ <parameter value="y_0=914398.5307444407"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24373" name="Kalianpur 1880 / India zone III">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=19"/>
+ <parameter value="lat_0=19"/>
+ <parameter value="lon_0=80"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.592233322"/>
+ <parameter value="y_0=914398.5307444407"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24374" name="Kalianpur 1880 / India zone IV">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=12"/>
+ <parameter value="lat_0=12"/>
+ <parameter value="lon_0=80"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.592233322"/>
+ <parameter value="y_0=914398.5307444407"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24375" name="Kalianpur 1937 / India zone IIb">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743185.69"/>
+ <parameter value="y_0=914395.23"/>
+ <parameter value="a=6377276.345"/>
+ <parameter value="b=6356075.413140239"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24376" name="Kalianpur 1962 / India zone I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.5"/>
+ <parameter value="lat_0=32.5"/>
+ <parameter value="lon_0=68"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743196.4"/>
+ <parameter value="y_0=914398.8"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24377" name="Kalianpur 1962 / India zone IIa">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=74"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743196.4"/>
+ <parameter value="y_0=914398.8"/>
+ <parameter value="a=6377301.243"/>
+ <parameter value="b=6356100.230165385"/>
+ <parameter value="towgs84=283,682,231,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24378" name="Kalianpur 1975 / India zone I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.5"/>
+ <parameter value="lat_0=32.5"/>
+ <parameter value="lon_0=68"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.5"/>
+ <parameter value="y_0=914398.5"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24379" name="Kalianpur 1975 / India zone IIa">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=74"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.5"/>
+ <parameter value="y_0=914398.5"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24380" name="Kalianpur 1975 / India zone IIb">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.5"/>
+ <parameter value="y_0=914398.5"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24381" name="Kalianpur 1975 / India zone III">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=19"/>
+ <parameter value="lat_0=19"/>
+ <parameter value="lon_0=80"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.5"/>
+ <parameter value="y_0=914398.5"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24382" name="Kalianpur 1880 / India zone IIb">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=90"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.592233322"/>
+ <parameter value="y_0=914398.5307444407"/>
+ <parameter value="a=6377299.36559538"/>
+ <parameter value="b=6356098.357204817"/>
+ <parameter value="to_meter=0.9143985307444408"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24383" name="Kalianpur 1975 / India zone IV">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=12"/>
+ <parameter value="lat_0=12"/>
+ <parameter value="lon_0=80"/>
+ <parameter value="k_0=0.99878641"/>
+ <parameter value="x_0=2743195.5"/>
+ <parameter value="y_0=914398.5"/>
+ <parameter value="a=6377299.151"/>
+ <parameter value="b=6356098.145120132"/>
+ <parameter value="towgs84=295,736,257,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24500" name="Kertau / Singapore Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=1.287646666666667"/>
+ <parameter value="lon_0=103.8530022222222"/>
+ <parameter value="x_0=30000"/>
+ <parameter value="y_0=30000"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="towgs84=-11,851,5,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24547" name="Kertau / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="towgs84=-11,851,5,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24548" name="Kertau / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="towgs84=-11,851,5,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24571" name="Kertau / R.S.O. Malaya (ch)">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lonc=102.25"/>
+ <parameter value="alpha=323.0257905"/>
+ <parameter value="k=0.99984"/>
+ <parameter value="x_0=804671.2997750348"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377304.063"/>
+ <parameter value="b=6356103.038993155"/>
+ <parameter value="towgs84=-11,851,5,0,0,0,0"/>
+ <parameter value="to_meter=20.11678249437587"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24600" name="KOC Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.5"/>
+ <parameter value="lat_0=32.5"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k_0=0.9987864078000001"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=1166200"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24718" name="La Canoa / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-273.5,110.6,-357.9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24719" name="La Canoa / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-273.5,110.6,-357.9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24720" name="La Canoa / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-273.5,110.6,-357.9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24818" name="PSAD56 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24819" name="PSAD56 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24820" name="PSAD56 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24821" name="PSAD56 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24877" name="PSAD56 / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24878" name="PSAD56 / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24879" name="PSAD56 / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24880" name="PSAD56 / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24882" name="PSAD56 / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24891" name="PSAD56 / Peru west zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-6"/>
+ <parameter value="lon_0=-80.5"/>
+ <parameter value="k=0.999830"/>
+ <parameter value="x_0=222000"/>
+ <parameter value="y_0=1426834.743"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24892" name="PSAD56 / Peru central zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-9.5"/>
+ <parameter value="lon_0=-76"/>
+ <parameter value="k=0.999330"/>
+ <parameter value="x_0=720000"/>
+ <parameter value="y_0=1039979.159"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="24893" name="PSAD56 / Peru east zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-9.5"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="k=0.999530"/>
+ <parameter value="x_0=1324000"/>
+ <parameter value="y_0=1040084.558"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25000" name="Leigon / Ghana Metre Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4.666666666666667"/>
+ <parameter value="lon_0=-1"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=274319.51"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="towgs84=-130,29,364,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25231" name="Lome / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25391" name="Luzon 1911 / Philippines zone I">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25392" name="Luzon 1911 / Philippines zone II">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=119"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25393" name="Luzon 1911 / Philippines zone III">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=121"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25394" name="Luzon 1911 / Philippines zone IV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25395" name="Luzon 1911 / Philippines zone V">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=125"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25700" name="Makassar (Jakarta) / NEIEZ">
+ <parameter value="proj=merc"/>
+ <parameter value="lat_ts=0"/>
+ <parameter value="lon_0=216.8077194444444"/>
+ <parameter value="k=0.997000"/>
+ <parameter value="x_0=3900000"/>
+ <parameter value="y_0=900000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=-587.8,519.75,145.76,0,0,0,0"/>
+ <parameter value="pm=jakarta"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25828" name="ETRS89 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25829" name="ETRS89 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25830" name="ETRS89 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25831" name="ETRS89 / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25832" name="ETRS89 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25833" name="ETRS89 / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25834" name="ETRS89 / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25835" name="ETRS89 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25836" name="ETRS89 / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25837" name="ETRS89 / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25838" name="ETRS89 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25884" name="ETRS89 / TM Baltic93">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="25932" name="Malongo 1987 / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26191" name="Merchich / Nord Maroc">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.3"/>
+ <parameter value="lat_0=33.3"/>
+ <parameter value="lon_0=-5.4"/>
+ <parameter value="k_0=0.999625769"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=31,146,47,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26192" name="Merchich / Sud Maroc">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=29.7"/>
+ <parameter value="lat_0=29.7"/>
+ <parameter value="lon_0=-5.4"/>
+ <parameter value="k_0=0.9996155960000001"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=31,146,47,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26193" name="Merchich / Sahara">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26.1"/>
+ <parameter value="lat_0=26.1"/>
+ <parameter value="lon_0=-5.4"/>
+ <parameter value="k_0=0.9996"/>
+ <parameter value="x_0=1200000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=31,146,47,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26237" name="Massawa / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="towgs84=639,405,60,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26331" name="Minna / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26332" name="Minna / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26391" name="Minna / Nigeria West Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lon_0=4.5"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=230738.26"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26392" name="Minna / Nigeria Mid Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lon_0=8.5"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=670553.98"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26393" name="Minna / Nigeria East Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lon_0=12.5"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=1110369.7"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26432" name="Mhast / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-252.95,-4.11,-96.38,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26591" name="Monte Mario (Rome) / Italy zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21.45233333333333"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=rome"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26592" name="Monte Mario (Rome) / Italy zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27.45233333333333"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=2520000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="pm=rome"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26632" name="M'poraloko / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26692" name="M'poraloko / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26703" name="NAD27 / UTM zone 3N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26704" name="NAD27 / UTM zone 4N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26705" name="NAD27 / UTM zone 5N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26706" name="NAD27 / UTM zone 6N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26707" name="NAD27 / UTM zone 7N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26708" name="NAD27 / UTM zone 8N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26709" name="NAD27 / UTM zone 9N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26710" name="NAD27 / UTM zone 10N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26711" name="NAD27 / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26712" name="NAD27 / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26713" name="NAD27 / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26714" name="NAD27 / UTM zone 14N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26715" name="NAD27 / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26716" name="NAD27 / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26717" name="NAD27 / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26718" name="NAD27 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26719" name="NAD27 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26720" name="NAD27 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26721" name="NAD27 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26722" name="NAD27 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26729" name="NAD27 / Alabama East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-85.83333333333333"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26730" name="NAD27 / Alabama West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-87.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26731" name="NAD27 / Alaska zone 1">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=57"/>
+ <parameter value="lonc=-133.6666666666667"/>
+ <parameter value="alpha=323.1301023611111"/>
+ <parameter value="k=0.9999"/>
+ <parameter value="x_0=5000000.001016002"/>
+ <parameter value="y_0=-5000000.001016002"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26732" name="NAD27 / Alaska zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-142"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26733" name="NAD27 / Alaska zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-146"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26734" name="NAD27 / Alaska zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-150"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26735" name="NAD27 / Alaska zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-154"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26736" name="NAD27 / Alaska zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-158"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26737" name="NAD27 / Alaska zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-162"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360.4267208534"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26738" name="NAD27 / Alaska zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-166"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26739" name="NAD27 / Alaska zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-170"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=182880.3657607315"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26740" name="NAD27 / Alaska zone 10">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=53.83333333333334"/>
+ <parameter value="lat_2=51.83333333333334"/>
+ <parameter value="lat_0=51"/>
+ <parameter value="lon_0=-176"/>
+ <parameter value="x_0=914401.8288036576"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26741" name="NAD27 / California zone I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.66666666666666"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26742" name="NAD27 / California zone II">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.83333333333334"/>
+ <parameter value="lat_2=38.33333333333334"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26743" name="NAD27 / California zone III">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.06666666666667"/>
+ <parameter value="lat_0=36.5"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26744" name="NAD27 / California zone IV">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.25"/>
+ <parameter value="lat_2=36"/>
+ <parameter value="lat_0=35.33333333333334"/>
+ <parameter value="lon_0=-119"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26745" name="NAD27 / California zone V">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.46666666666667"/>
+ <parameter value="lat_2=34.03333333333333"/>
+ <parameter value="lat_0=33.5"/>
+ <parameter value="lon_0=-118"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26746" name="NAD27 / California zone VI">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.88333333333333"/>
+ <parameter value="lat_2=32.78333333333333"/>
+ <parameter value="lat_0=32.16666666666666"/>
+ <parameter value="lon_0=-116.25"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26747" name="NAD27 / California zone VII">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.41666666666666"/>
+ <parameter value="lat_2=33.86666666666667"/>
+ <parameter value="lat_0=34.13333333333333"/>
+ <parameter value="lon_0=-118.3333333333333"/>
+ <parameter value="x_0=1276106.450596901"/>
+ <parameter value="y_0=127079.524511049"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26748" name="NAD27 / Arizona East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-110.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26749" name="NAD27 / Arizona Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-111.9166666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26750" name="NAD27 / Arizona West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-113.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26751" name="NAD27 / Arkansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.23333333333333"/>
+ <parameter value="lat_2=34.93333333333333"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26752" name="NAD27 / Arkansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.76666666666667"/>
+ <parameter value="lat_2=33.3"/>
+ <parameter value="lat_0=32.66666666666666"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26753" name="NAD27 / Colorado North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.71666666666667"/>
+ <parameter value="lat_2=40.78333333333333"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26754" name="NAD27 / Colorado Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.75"/>
+ <parameter value="lat_2=38.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26755" name="NAD27 / Colorado South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.23333333333333"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26756" name="NAD27 / Connecticut">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.86666666666667"/>
+ <parameter value="lat_2=41.2"/>
+ <parameter value="lat_0=40.83333333333334"/>
+ <parameter value="lon_0=-72.75"/>
+ <parameter value="x_0=182880.3657607315"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26757" name="NAD27 / Delaware">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-75.41666666666667"/>
+ <parameter value="k=0.999995"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26758" name="NAD27 / Florida East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26759" name="NAD27 / Florida West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-82"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26760" name="NAD27 / Florida North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.75"/>
+ <parameter value="lat_2=29.58333333333333"/>
+ <parameter value="lat_0=29"/>
+ <parameter value="lon_0=-84.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26766" name="NAD27 / Georgia East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-82.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26767" name="NAD27 / Georgia West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-84.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26768" name="NAD27 / Idaho East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-112.1666666666667"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26769" name="NAD27 / Idaho Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-114"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26770" name="NAD27 / Idaho West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-115.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26771" name="NAD27 / Illinois East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-88.33333333333333"/>
+ <parameter value="k=0.999975"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26772" name="NAD27 / Illinois West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-90.16666666666667"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26773" name="NAD27 / Indiana East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-85.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26774" name="NAD27 / Indiana West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-87.08333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26775" name="NAD27 / Iowa North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.26666666666667"/>
+ <parameter value="lat_2=42.06666666666667"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26776" name="NAD27 / Iowa South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.61666666666667"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26777" name="NAD27 / Kansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.78333333333333"/>
+ <parameter value="lat_2=38.71666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26778" name="NAD27 / Kansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.56666666666667"/>
+ <parameter value="lat_2=37.26666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26779" name="NAD27 / Kentucky North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=38.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26780" name="NAD27 / Kentucky South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.73333333333333"/>
+ <parameter value="lat_2=37.93333333333333"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26781" name="NAD27 / Louisiana North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=31.16666666666667"/>
+ <parameter value="lat_2=32.66666666666666"/>
+ <parameter value="lat_0=30.66666666666667"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26782" name="NAD27 / Louisiana South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=29.3"/>
+ <parameter value="lat_2=30.7"/>
+ <parameter value="lat_0=28.66666666666667"/>
+ <parameter value="lon_0=-91.33333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26783" name="NAD27 / Maine East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26784" name="NAD27 / Maine West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.83333333333334"/>
+ <parameter value="lon_0=-70.16666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26785" name="NAD27 / Maryland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.3"/>
+ <parameter value="lat_2=39.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="x_0=243840.4876809754"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26786" name="NAD27 / Massachusetts Mainland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.71666666666667"/>
+ <parameter value="lat_2=42.68333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="x_0=182880.3657607315"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26787" name="NAD27 / Massachusetts Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.28333333333333"/>
+ <parameter value="lat_2=41.48333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="x_0=60960.12192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26791" name="NAD27 / Minnesota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.03333333333333"/>
+ <parameter value="lat_2=48.63333333333333"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-93.09999999999999"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26792" name="NAD27 / Minnesota Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.61666666666667"/>
+ <parameter value="lat_2=47.05"/>
+ <parameter value="lat_0=45"/>
+ <parameter value="lon_0=-94.25"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26793" name="NAD27 / Minnesota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.78333333333333"/>
+ <parameter value="lat_2=45.21666666666667"/>
+ <parameter value="lat_0=43"/>
+ <parameter value="lon_0=-94"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26794" name="NAD27 / Mississippi East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-88.83333333333333"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26795" name="NAD27 / Mississippi West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26796" name="NAD27 / Missouri East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-90.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26797" name="NAD27 / Missouri Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26798" name="NAD27 / Missouri West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.16666666666666"/>
+ <parameter value="lon_0=-94.5"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26801" name="NAD Michigan / Michigan East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-83.66666666666667"/>
+ <parameter value="k=0.999943"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26802" name="NAD Michigan / Michigan Old Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26803" name="NAD Michigan / Michigan West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-88.75"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26811" name="NAD Michigan / Michigan North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.48333333333333"/>
+ <parameter value="lat_2=47.08333333333334"/>
+ <parameter value="lat_0=44.78333333333333"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26812" name="NAD Michigan / Michigan Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.18333333333333"/>
+ <parameter value="lat_2=45.7"/>
+ <parameter value="lat_0=43.31666666666667"/>
+ <parameter value="lon_0=-84.33333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26813" name="NAD Michigan / Michigan South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.1"/>
+ <parameter value="lat_2=43.66666666666666"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-84.33333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6378450.047548896"/>
+ <parameter value="b=6356826.621488444"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26903" name="NAD83 / UTM zone 3N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26904" name="NAD83 / UTM zone 4N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26905" name="NAD83 / UTM zone 5N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26906" name="NAD83 / UTM zone 6N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26907" name="NAD83 / UTM zone 7N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26908" name="NAD83 / UTM zone 8N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26909" name="NAD83 / UTM zone 9N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26910" name="NAD83 / UTM zone 10N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26911" name="NAD83 / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26912" name="NAD83 / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26913" name="NAD83 / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26914" name="NAD83 / UTM zone 14N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26915" name="NAD83 / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26916" name="NAD83 / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26917" name="NAD83 / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26918" name="NAD83 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26919" name="NAD83 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26920" name="NAD83 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26921" name="NAD83 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26922" name="NAD83 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26923" name="NAD83 / UTM zone 23N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26929" name="NAD83 / Alabama East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-85.83333333333333"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26930" name="NAD83 / Alabama West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-87.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26931" name="NAD83 / Alaska zone 1">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=57"/>
+ <parameter value="lonc=-133.6666666666667"/>
+ <parameter value="alpha=323.1301023611111"/>
+ <parameter value="k=0.9999"/>
+ <parameter value="x_0=5000000"/>
+ <parameter value="y_0=-5000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26932" name="NAD83 / Alaska zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-142"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26933" name="NAD83 / Alaska zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-146"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26934" name="NAD83 / Alaska zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-150"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26935" name="NAD83 / Alaska zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-154"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26936" name="NAD83 / Alaska zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-158"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26937" name="NAD83 / Alaska zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-162"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26938" name="NAD83 / Alaska zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-166"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26939" name="NAD83 / Alaska zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=54"/>
+ <parameter value="lon_0=-170"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26940" name="NAD83 / Alaska zone 10">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=53.83333333333334"/>
+ <parameter value="lat_2=51.83333333333334"/>
+ <parameter value="lat_0=51"/>
+ <parameter value="lon_0=-176"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26941" name="NAD83 / California zone 1">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.66666666666666"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26942" name="NAD83 / California zone 2">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.83333333333334"/>
+ <parameter value="lat_2=38.33333333333334"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-122"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26943" name="NAD83 / California zone 3">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.06666666666667"/>
+ <parameter value="lat_0=36.5"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26944" name="NAD83 / California zone 4">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.25"/>
+ <parameter value="lat_2=36"/>
+ <parameter value="lat_0=35.33333333333334"/>
+ <parameter value="lon_0=-119"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26945" name="NAD83 / California zone 5">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.46666666666667"/>
+ <parameter value="lat_2=34.03333333333333"/>
+ <parameter value="lat_0=33.5"/>
+ <parameter value="lon_0=-118"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26946" name="NAD83 / California zone 6">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.88333333333333"/>
+ <parameter value="lat_2=32.78333333333333"/>
+ <parameter value="lat_0=32.16666666666666"/>
+ <parameter value="lon_0=-116.25"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26948" name="NAD83 / Arizona East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-110.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26949" name="NAD83 / Arizona Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-111.9166666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26950" name="NAD83 / Arizona West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-113.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=213360"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26951" name="NAD83 / Arkansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.23333333333333"/>
+ <parameter value="lat_2=34.93333333333333"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26952" name="NAD83 / Arkansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.76666666666667"/>
+ <parameter value="lat_2=33.3"/>
+ <parameter value="lat_0=32.66666666666666"/>
+ <parameter value="lon_0=-92"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26953" name="NAD83 / Colorado North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.78333333333333"/>
+ <parameter value="lat_2=39.71666666666667"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26954" name="NAD83 / Colorado Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.75"/>
+ <parameter value="lat_2=38.45"/>
+ <parameter value="lat_0=37.83333333333334"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26955" name="NAD83 / Colorado South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.43333333333333"/>
+ <parameter value="lat_2=37.23333333333333"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-105.5"/>
+ <parameter value="x_0=914401.8289"/>
+ <parameter value="y_0=304800.6096"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26956" name="NAD83 / Connecticut">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.86666666666667"/>
+ <parameter value="lat_2=41.2"/>
+ <parameter value="lat_0=40.83333333333334"/>
+ <parameter value="lon_0=-72.75"/>
+ <parameter value="x_0=304800.6096"/>
+ <parameter value="y_0=152400.3048"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26957" name="NAD83 / Delaware">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-75.41666666666667"/>
+ <parameter value="k=0.999995"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26958" name="NAD83 / Florida East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26959" name="NAD83 / Florida West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.33333333333333"/>
+ <parameter value="lon_0=-82"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26960" name="NAD83 / Florida North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.75"/>
+ <parameter value="lat_2=29.58333333333333"/>
+ <parameter value="lat_0=29"/>
+ <parameter value="lon_0=-84.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26961" name="NAD83 / Hawaii zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=18.83333333333333"/>
+ <parameter value="lon_0=-155.5"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26962" name="NAD83 / Hawaii zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=20.33333333333333"/>
+ <parameter value="lon_0=-156.6666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26963" name="NAD83 / Hawaii zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.16666666666667"/>
+ <parameter value="lon_0=-158"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26964" name="NAD83 / Hawaii zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.83333333333333"/>
+ <parameter value="lon_0=-159.5"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26965" name="NAD83 / Hawaii zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=21.66666666666667"/>
+ <parameter value="lon_0=-160.1666666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26966" name="NAD83 / Georgia East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-82.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26967" name="NAD83 / Georgia West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=30"/>
+ <parameter value="lon_0=-84.16666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26968" name="NAD83 / Idaho East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-112.1666666666667"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26969" name="NAD83 / Idaho Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-114"/>
+ <parameter value="k=0.999947"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26970" name="NAD83 / Idaho West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-115.75"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26971" name="NAD83 / Illinois East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-88.33333333333333"/>
+ <parameter value="k=0.999975"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26972" name="NAD83 / Illinois West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-90.16666666666667"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26973" name="NAD83 / Indiana East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-85.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=100000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26974" name="NAD83 / Indiana West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-87.08333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26975" name="NAD83 / Iowa North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.26666666666667"/>
+ <parameter value="lat_2=42.06666666666667"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26976" name="NAD83 / Iowa South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.61666666666667"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-93.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26977" name="NAD83 / Kansas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.78333333333333"/>
+ <parameter value="lat_2=38.71666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26978" name="NAD83 / Kansas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.56666666666667"/>
+ <parameter value="lat_2=37.26666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26979" name="NAD83 / Kentucky North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=37.96666666666667"/>
+ <parameter value="lat_0=37.5"/>
+ <parameter value="lon_0=-84.25"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26980" name="NAD83 / Kentucky South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.93333333333333"/>
+ <parameter value="lat_2=36.73333333333333"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-85.75"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26981" name="NAD83 / Louisiana North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.66666666666666"/>
+ <parameter value="lat_2=31.16666666666667"/>
+ <parameter value="lat_0=30.5"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26982" name="NAD83 / Louisiana South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.7"/>
+ <parameter value="lat_2=29.3"/>
+ <parameter value="lat_0=28.5"/>
+ <parameter value="lon_0=-91.33333333333333"/>
+ <parameter value="x_0=1000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26983" name="NAD83 / Maine East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26984" name="NAD83 / Maine West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.83333333333334"/>
+ <parameter value="lon_0=-70.16666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=900000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26985" name="NAD83 / Maryland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.45"/>
+ <parameter value="lat_2=38.3"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-77"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26986" name="NAD83 / Massachusetts Mainland">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.68333333333333"/>
+ <parameter value="lat_2=41.71666666666667"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=750000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26987" name="NAD83 / Massachusetts Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.48333333333333"/>
+ <parameter value="lat_2=41.28333333333333"/>
+ <parameter value="lat_0=41"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26988" name="NAD83 / Michigan North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.08333333333334"/>
+ <parameter value="lat_2=45.48333333333333"/>
+ <parameter value="lat_0=44.78333333333333"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="x_0=8000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26989" name="NAD83 / Michigan Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.7"/>
+ <parameter value="lat_2=44.18333333333333"/>
+ <parameter value="lat_0=43.31666666666667"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=6000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26990" name="NAD83 / Michigan South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43.66666666666666"/>
+ <parameter value="lat_2=42.1"/>
+ <parameter value="lat_0=41.5"/>
+ <parameter value="lon_0=-84.36666666666666"/>
+ <parameter value="x_0=4000000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26991" name="NAD83 / Minnesota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.63333333333333"/>
+ <parameter value="lat_2=47.03333333333333"/>
+ <parameter value="lat_0=46.5"/>
+ <parameter value="lon_0=-93.09999999999999"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26992" name="NAD83 / Minnesota Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.05"/>
+ <parameter value="lat_2=45.61666666666667"/>
+ <parameter value="lat_0=45"/>
+ <parameter value="lon_0=-94.25"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26993" name="NAD83 / Minnesota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.21666666666667"/>
+ <parameter value="lat_2=43.78333333333333"/>
+ <parameter value="lat_0=43"/>
+ <parameter value="lon_0=-94"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26994" name="NAD83 / Mississippi East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-88.83333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26995" name="NAD83 / Mississippi West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=29.5"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k=0.999950"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26996" name="NAD83 / Missouri East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-90.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=250000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26997" name="NAD83 / Missouri Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=35.83333333333334"/>
+ <parameter value="lon_0=-92.5"/>
+ <parameter value="k=0.999933"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="26998" name="NAD83 / Missouri West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36.16666666666666"/>
+ <parameter value="lon_0=-94.5"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=850000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27038" name="Nahrwan 1967 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27039" name="Nahrwan 1967 / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27040" name="Nahrwan 1967 / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27120" name="Naparima 1972 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27200" name="NZGD49 / New Zealand Map Grid">
+ <parameter value="proj=nzmg"/>
+ <parameter value="lat_0=-41"/>
+ <parameter value="lon_0=173"/>
+ <parameter value="x_0=2510000"/>
+ <parameter value="y_0=6023150"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27205" name="NZGD49 / Mount Eden Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-36.87986527777778"/>
+ <parameter value="lon_0=174.7643393611111"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27206" name="NZGD49 / Bay of Plenty Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-37.76124980555556"/>
+ <parameter value="lon_0=176.46619725"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27207" name="NZGD49 / Poverty Bay Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-38.62470277777778"/>
+ <parameter value="lon_0=177.8856362777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27208" name="NZGD49 / Hawkes Bay Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.65092930555556"/>
+ <parameter value="lon_0=176.6736805277778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27209" name="NZGD49 / Taranaki Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.13575830555556"/>
+ <parameter value="lon_0=174.22801175"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27210" name="NZGD49 / Tuhirangi Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39.51247038888889"/>
+ <parameter value="lon_0=175.6400368055556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27211" name="NZGD49 / Wanganui Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.24194713888889"/>
+ <parameter value="lon_0=175.4880996111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27212" name="NZGD49 / Wairarapa Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.92553263888889"/>
+ <parameter value="lon_0=175.6473496666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27213" name="NZGD49 / Wellington Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.30131963888888"/>
+ <parameter value="lon_0=174.7766231111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27214" name="NZGD49 / Collingwood Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-40.71475905555556"/>
+ <parameter value="lon_0=172.6720465"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27215" name="NZGD49 / Nelson Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.27454472222222"/>
+ <parameter value="lon_0=173.2993168055555"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27216" name="NZGD49 / Karamea Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.28991152777778"/>
+ <parameter value="lon_0=172.1090281944444"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27217" name="NZGD49 / Buller Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.81080286111111"/>
+ <parameter value="lon_0=171.5812600555556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27218" name="NZGD49 / Grey Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.33369427777778"/>
+ <parameter value="lon_0=171.5497713055556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27219" name="NZGD49 / Amuri Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.68911658333333"/>
+ <parameter value="lon_0=173.0101333888889"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27220" name="NZGD49 / Marlborough Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-41.54448666666666"/>
+ <parameter value="lon_0=173.8020741111111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27221" name="NZGD49 / Hokitika Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-42.88632236111111"/>
+ <parameter value="lon_0=170.9799935"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27222" name="NZGD49 / Okarito Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.11012813888889"/>
+ <parameter value="lon_0=170.2609258333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27223" name="NZGD49 / Jacksons Bay Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.97780288888889"/>
+ <parameter value="lon_0=168.606267"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27224" name="NZGD49 / Mount Pleasant Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.59063758333333"/>
+ <parameter value="lon_0=172.7271935833333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27225" name="NZGD49 / Gawler Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-43.74871155555556"/>
+ <parameter value="lon_0=171.3607484722222"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27226" name="NZGD49 / Timaru Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-44.40222036111111"/>
+ <parameter value="lon_0=171.0572508333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27227" name="NZGD49 / Lindis Peak Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-44.73526797222222"/>
+ <parameter value="lon_0=169.4677550833333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27228" name="NZGD49 / Mount Nicholas Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.13290258333333"/>
+ <parameter value="lon_0=168.3986411944444"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27229" name="NZGD49 / Mount York Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.56372616666666"/>
+ <parameter value="lon_0=167.7388617777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27230" name="NZGD49 / Observation Point Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.81619661111111"/>
+ <parameter value="lon_0=170.6285951666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27231" name="NZGD49 / North Taieri Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-45.86151336111111"/>
+ <parameter value="lon_0=170.2825891111111"/>
+ <parameter value="k=0.999960"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=700000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27232" name="NZGD49 / Bluff Circuit">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-46.60000961111111"/>
+ <parameter value="lon_0=168.342872"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=300002.66"/>
+ <parameter value="y_0=699999.58"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27258" name="NZGD49 / UTM zone 58S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27259" name="NZGD49 / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27260" name="NZGD49 / UTM zone 60S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27291" name="NZGD49 / North Island Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-39"/>
+ <parameter value="lon_0=175.5"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=274319.5243848086"/>
+ <parameter value="y_0=365759.3658464114"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="to_meter=0.9143984146160287"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27292" name="NZGD49 / South Island Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=-44"/>
+ <parameter value="lon_0=171.5"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=457199.2073080143"/>
+ <parameter value="y_0=457199.2073080143"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="to_meter=0.9143984146160287"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27391" name="NGO 1948 (Oslo) / NGO zone I">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=6.056250000000003"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27392" name="NGO 1948 (Oslo) / NGO zone II">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=8.389583333333336"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27393" name="NGO 1948 (Oslo) / NGO zone III">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=10.72291666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27394" name="NGO 1948 (Oslo) / NGO zone IV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=13.22291666666667"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27395" name="NGO 1948 (Oslo) / NGO zone V">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=16.88958333333334"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27396" name="NGO 1948 (Oslo) / NGO zone VI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=20.88958333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27397" name="NGO 1948 (Oslo) / NGO zone VII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=24.88958333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27398" name="NGO 1948 (Oslo) / NGO zone VIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=58"/>
+ <parameter value="lon_0=29.05625"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="a=6377492.018"/>
+ <parameter value="b=6356173.508712696"/>
+ <parameter value="towgs84=278.3,93,474.5,7.889,0.05,-6.61,6.21"/>
+ <parameter value="pm=oslo"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27429" name="Datum 73 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27492" name="Datum 73 / Modified Portuguese Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-8.131906111111112"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=180.598"/>
+ <parameter value="y_0=-86.98999999999999"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27500" name="ATF (Paris) / Nord de Guerre">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.50000000000001"/>
+ <parameter value="lat_0=49.50000000000001"/>
+ <parameter value="lon_0=7.737229170000001"/>
+ <parameter value="k_0=0.99950908"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6376523"/>
+ <parameter value="b=6355862.933255573"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27561" name="NTF (Paris) / Lambert Nord France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.50000000000001"/>
+ <parameter value="lat_0=49.50000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877341"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27562" name="NTF (Paris) / Lambert Centre France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.8"/>
+ <parameter value="lat_0=46.8"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99987742"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27563" name="NTF (Paris) / Lambert Sud France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.10000000000001"/>
+ <parameter value="lat_0=44.10000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877499"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27564" name="NTF (Paris) / Lambert Corse">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.16500000000001"/>
+ <parameter value="lat_0=42.16500000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99994471"/>
+ <parameter value="x_0=234.358"/>
+ <parameter value="y_0=185861.369"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27571" name="NTF (Paris) / Lambert zone I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.50000000000001"/>
+ <parameter value="lat_0=49.50000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877341"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=1200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27572" name="NTF (Paris) / Lambert zone II">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.8"/>
+ <parameter value="lat_0=46.8"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99987742"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27573" name="NTF (Paris) / Lambert zone III">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.10000000000001"/>
+ <parameter value="lat_0=44.10000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877499"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=3200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27574" name="NTF (Paris) / Lambert zone IV">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.16500000000001"/>
+ <parameter value="lat_0=42.16500000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99994471"/>
+ <parameter value="x_0=234.358"/>
+ <parameter value="y_0=4185861.369"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27581" name="NTF (Paris) / France I">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.50000000000001"/>
+ <parameter value="lat_0=49.50000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877341"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=1200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27582" name="NTF (Paris) / France II">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.8"/>
+ <parameter value="lat_0=46.8"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99987742"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27583" name="NTF (Paris) / France III">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.10000000000001"/>
+ <parameter value="lat_0=44.10000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877499"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=3200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27584" name="NTF (Paris) / France IV">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.16500000000001"/>
+ <parameter value="lat_0=42.16500000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99994471"/>
+ <parameter value="x_0=234.358"/>
+ <parameter value="y_0=4185861.369"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27591" name="NTF (Paris) / Nord France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.50000000000001"/>
+ <parameter value="lat_0=49.50000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877341"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27592" name="NTF (Paris) / Centre France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.8"/>
+ <parameter value="lat_0=46.8"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99987742"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27593" name="NTF (Paris) / Sud France">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.10000000000001"/>
+ <parameter value="lat_0=44.10000000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.999877499"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27594" name="NTF (Paris) / Corse">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.16500000000001"/>
+ <parameter value="lat_0=42.16500000000001"/>
+ <parameter value="lon_0=2.33722917"/>
+ <parameter value="k_0=0.99994471"/>
+ <parameter value="x_0=234.358"/>
+ <parameter value="y_0=185861.369"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-168,-60,320,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="27700" name="OSGB 1936 / British National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=49"/>
+ <parameter value="lon_0=-2"/>
+ <parameter value="k=0.999601"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=-100000"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28191" name="Palestine 1923 / Palestine Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=31.73409694444445"/>
+ <parameter value="lon_0=35.21208055555556"/>
+ <parameter value="x_0=170251.555"/>
+ <parameter value="y_0=126867.909"/>
+ <parameter value="a=6378300.789"/>
+ <parameter value="b=6356566.435"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28192" name="Palestine 1923 / Palestine Belt">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31.73409694444445"/>
+ <parameter value="lon_0=35.21208055555556"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=170251.555"/>
+ <parameter value="y_0=1126867.909"/>
+ <parameter value="a=6378300.789"/>
+ <parameter value="b=6356566.435"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28193" name="Palestine 1923 / Israeli CS Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=31.73409694444445"/>
+ <parameter value="lon_0=35.21208055555556"/>
+ <parameter value="x_0=170251.555"/>
+ <parameter value="y_0=1126867.909"/>
+ <parameter value="a=6378300.789"/>
+ <parameter value="b=6356566.435"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28232" name="Pointe Noire / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28348" name="GDA94 / MGA zone 48">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28349" name="GDA94 / MGA zone 49">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28350" name="GDA94 / MGA zone 50">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28351" name="GDA94 / MGA zone 51">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28352" name="GDA94 / MGA zone 52">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28353" name="GDA94 / MGA zone 53">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28354" name="GDA94 / MGA zone 54">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28355" name="GDA94 / MGA zone 55">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28356" name="GDA94 / MGA zone 56">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28357" name="GDA94 / MGA zone 57">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28358" name="GDA94 / MGA zone 58">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28402" name="Pulkovo 1942 / Gauss-Kruger zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28403" name="Pulkovo 1942 / Gauss-Kruger zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28404" name="Pulkovo 1942 / Gauss-Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28405" name="Pulkovo 1942 / Gauss-Kruger zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28406" name="Pulkovo 1942 / Gauss-Kruger zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28407" name="Pulkovo 1942 / Gauss-Kruger zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28408" name="Pulkovo 1942 / Gauss-Kruger zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28409" name="Pulkovo 1942 / Gauss-Kruger zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=9500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28410" name="Pulkovo 1942 / Gauss-Kruger zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=10500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28411" name="Pulkovo 1942 / Gauss-Kruger zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=11500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28412" name="Pulkovo 1942 / Gauss-Kruger zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=12500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28413" name="Pulkovo 1942 / Gauss-Kruger zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=13500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28414" name="Pulkovo 1942 / Gauss-Kruger zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=14500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28415" name="Pulkovo 1942 / Gauss-Kruger zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=15500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28416" name="Pulkovo 1942 / Gauss-Kruger zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=16500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28417" name="Pulkovo 1942 / Gauss-Kruger zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=17500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28418" name="Pulkovo 1942 / Gauss-Kruger zone 18">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=18500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28419" name="Pulkovo 1942 / Gauss-Kruger zone 19">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=19500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28420" name="Pulkovo 1942 / Gauss-Kruger zone 20">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=20500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28421" name="Pulkovo 1942 / Gauss-Kruger zone 21">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=21500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28422" name="Pulkovo 1942 / Gauss-Kruger zone 22">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=22500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28423" name="Pulkovo 1942 / Gauss-Kruger zone 23">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=23500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28424" name="Pulkovo 1942 / Gauss-Kruger zone 24">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=24500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28425" name="Pulkovo 1942 / Gauss-Kruger zone 25">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=25500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28426" name="Pulkovo 1942 / Gauss-Kruger zone 26">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=26500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28427" name="Pulkovo 1942 / Gauss-Kruger zone 27">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=27500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28428" name="Pulkovo 1942 / Gauss-Kruger zone 28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=28500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28429" name="Pulkovo 1942 / Gauss-Kruger zone 29">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=29500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28430" name="Pulkovo 1942 / Gauss-Kruger zone 30">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=30500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28431" name="Pulkovo 1942 / Gauss-Kruger zone 31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=31500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28432" name="Pulkovo 1942 / Gauss-Kruger zone 32">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=32500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28462" name="Pulkovo 1942 / Gauss-Kruger 2N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28463" name="Pulkovo 1942 / Gauss-Kruger 3N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28464" name="Pulkovo 1942 / Gauss-Kruger 4N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28465" name="Pulkovo 1942 / Gauss-Kruger 5N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=27"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28466" name="Pulkovo 1942 / Gauss-Kruger 6N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=33"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28467" name="Pulkovo 1942 / Gauss-Kruger 7N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=39"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28468" name="Pulkovo 1942 / Gauss-Kruger 8N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=45"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28469" name="Pulkovo 1942 / Gauss-Kruger 9N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=51"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28470" name="Pulkovo 1942 / Gauss-Kruger 10N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=57"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28471" name="Pulkovo 1942 / Gauss-Kruger 11N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=63"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28472" name="Pulkovo 1942 / Gauss-Kruger 12N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=69"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28473" name="Pulkovo 1942 / Gauss-Kruger 13N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=75"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28474" name="Pulkovo 1942 / Gauss-Kruger 14N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=81"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28475" name="Pulkovo 1942 / Gauss-Kruger 15N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=87"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28476" name="Pulkovo 1942 / Gauss-Kruger 16N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=93"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28477" name="Pulkovo 1942 / Gauss-Kruger 17N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=99"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28478" name="Pulkovo 1942 / Gauss-Kruger 18N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=105"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28479" name="Pulkovo 1942 / Gauss-Kruger 19N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=111"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28480" name="Pulkovo 1942 / Gauss-Kruger 20N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=117"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28481" name="Pulkovo 1942 / Gauss-Kruger 21N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=123"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28482" name="Pulkovo 1942 / Gauss-Kruger 22N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=129"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28483" name="Pulkovo 1942 / Gauss-Kruger 23N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=135"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28484" name="Pulkovo 1942 / Gauss-Kruger 24N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=141"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28485" name="Pulkovo 1942 / Gauss-Kruger 25N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=147"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28486" name="Pulkovo 1942 / Gauss-Kruger 26N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=153"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28487" name="Pulkovo 1942 / Gauss-Kruger 27N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=159"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28488" name="Pulkovo 1942 / Gauss-Kruger 28N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=165"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28489" name="Pulkovo 1942 / Gauss-Kruger 29N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28490" name="Pulkovo 1942 / Gauss-Kruger 30N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28491" name="Pulkovo 1942 / Gauss-Kruger 31N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-177"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28492" name="Pulkovo 1942 / Gauss-Kruger 32N">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-171"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28600" name="Qatar 1974 / Qatar National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=24.45"/>
+ <parameter value="lon_0=51.21666666666667"/>
+ <parameter value="k=0.999990"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28991" name="Amersfoort / RD Old">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=52.15616055555555"/>
+ <parameter value="lon_0=5.38763888888889"/>
+ <parameter value="k=0.999908"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="28992" name="Amersfoort / RD New">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=52.15616055555555"/>
+ <parameter value="lon_0=5.38763888888889"/>
+ <parameter value="k=0.999908"/>
+ <parameter value="x_0=155000"/>
+ <parameter value="y_0=463000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29100" name="SAD69 / Brazil Polyconic">
+ <parameter value="proj=poly"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-54"/>
+ <parameter value="x_0=5000000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29118" name="SAD69 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29119" name="SAD69 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29120" name="SAD69 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29121" name="SAD69 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29122" name="SAD69 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29177" name="SAD69 / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29178" name="SAD69 / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29179" name="SAD69 / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29180" name="SAD69 / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29181" name="SAD69 / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29182" name="SAD69 / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29183" name="SAD69 / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29184" name="SAD69 / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29185" name="SAD69 / UTM zone 25S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS67"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29220" name="Sapper Hill 1943 / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-355,21,72,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29221" name="Sapper Hill 1943 / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-355,21,72,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29333" name="Schwarzeck / UTM zone 33S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="south"/>
+ <parameter value="ellps=bess_nam"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29635" name="Sudan / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29636" name="Sudan / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29700" name="Tananarive (Paris) / Laborde Grid">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=-18.9"/>
+ <parameter value="lonc=46.43722917000001"/>
+ <parameter value="alpha=18.9"/>
+ <parameter value="k=0.9995000000000001"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=800000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-189,-242,-91,0,0,0,0"/>
+ <parameter value="pm=paris"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29738" name="Tananarive / UTM zone 38S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-189,-242,-91,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29739" name="Tananarive / UTM zone 39S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="south"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-189,-242,-91,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29849" name="Timbalai 1948 / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29850" name="Timbalai 1948 / UTM zone 50N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29871" name="Timbalai 1948 / R.S.O. Borneo (ch)">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lonc=115"/>
+ <parameter value="alpha=53.31582047222222"/>
+ <parameter value="k=0.99984"/>
+ <parameter value="x_0=590476.8714630401"/>
+ <parameter value="y_0=442857.653094361"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="to_meter=20.11676512155263"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29872" name="Timbalai 1948 / R.S.O. Borneo (ft)">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lonc=115"/>
+ <parameter value="alpha=53.31582047222222"/>
+ <parameter value="k=0.99984"/>
+ <parameter value="x_0=590476.8727431979"/>
+ <parameter value="y_0=442857.6545573985"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="to_meter=0.3047994715386762"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29873" name="Timbalai 1948 / R.S.O. Borneo (m)">
+ <parameter value="proj=omerc"/>
+ <parameter value="lat_0=4"/>
+ <parameter value="lonc=115"/>
+ <parameter value="alpha=53.31582047222222"/>
+ <parameter value="k=0.99984"/>
+ <parameter value="x_0=590476.87"/>
+ <parameter value="y_0=442857.65"/>
+ <parameter value="ellps=evrstSS"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29900" name="TM65 / Irish National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=53.5"/>
+ <parameter value="lon_0=-8"/>
+ <parameter value="k=1.000035"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29901" name="OSNI 1952 / Irish National Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=53.5"/>
+ <parameter value="lon_0=-8"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="ellps=airy"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29902" name="TM65 / Irish Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=53.5"/>
+ <parameter value="lon_0=-8"/>
+ <parameter value="k=1.000035"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="29903" name="TM75 / Irish Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=53.5"/>
+ <parameter value="lon_0=-8"/>
+ <parameter value="k=1.000035"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=250000"/>
+ <parameter value="a=6377340.189"/>
+ <parameter value="b=6356034.447938534"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30161" name="Tokyo / Japan Plane Rectangular CS I">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=129.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30162" name="Tokyo / Japan Plane Rectangular CS II">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=131"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30163" name="Tokyo / Japan Plane Rectangular CS III">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=132.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30164" name="Tokyo / Japan Plane Rectangular CS IV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=133.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30165" name="Tokyo / Japan Plane Rectangular CS V">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=134.3333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30166" name="Tokyo / Japan Plane Rectangular CS VI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=136"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30167" name="Tokyo / Japan Plane Rectangular CS VII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=137.1666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30168" name="Tokyo / Japan Plane Rectangular CS VIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=138.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30169" name="Tokyo / Japan Plane Rectangular CS IX">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=139.8333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30170" name="Tokyo / Japan Plane Rectangular CS X">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=140.8333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30171" name="Tokyo / Japan Plane Rectangular CS XI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=140.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30172" name="Tokyo / Japan Plane Rectangular CS XII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=142.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30173" name="Tokyo / Japan Plane Rectangular CS XIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=144.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30174" name="Tokyo / Japan Plane Rectangular CS XIV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=142"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30175" name="Tokyo / Japan Plane Rectangular CS XV">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=127.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30176" name="Tokyo / Japan Plane Rectangular CS XVI">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=124"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30177" name="Tokyo / Japan Plane Rectangular CS XVII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=131"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30178" name="Tokyo / Japan Plane Rectangular CS XVIII">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=20"/>
+ <parameter value="lon_0=136"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30179" name="Tokyo / Japan Plane Rectangular CS XIX">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=26"/>
+ <parameter value="lon_0=154"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30200" name="Trinidad 1903 / Trinidad Grid">
+ <parameter value="proj=cass"/>
+ <parameter value="lat_0=10.44166666666667"/>
+ <parameter value="lon_0=-61.33333333333334"/>
+ <parameter value="x_0=86501.46380700001"/>
+ <parameter value="y_0=65379.0133425"/>
+ <parameter value="a=6378293.63683822"/>
+ <parameter value="b=6356617.979337744"/>
+ <parameter value="towgs84=-61.702,284.488,472.052,0,0,0,0"/>
+ <parameter value="to_meter=0.2011661949"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30339" name="TC(1948) / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30340" name="TC(1948) / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=helmert"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30491" name="Voirol 1875 / Nord Algerie (ancienne)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=2.7"/>
+ <parameter value="k_0=0.999625544"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-73,-247,227,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30492" name="Voirol 1875 / Sud Algerie (ancienne)">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.3"/>
+ <parameter value="lat_0=33.3"/>
+ <parameter value="lon_0=2.7"/>
+ <parameter value="k_0=0.999625769"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=300000"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-73,-247,227,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30729" name="Nord Sahara 1959 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30730" name="Nord Sahara 1959 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30731" name="Nord Sahara 1959 / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30732" name="Nord Sahara 1959 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30791" name="Nord Sahara 1959 / Voirol Unifie Nord">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36"/>
+ <parameter value="lat_0=36"/>
+ <parameter value="lon_0=2.7"/>
+ <parameter value="k_0=0.999625544"/>
+ <parameter value="x_0=500135"/>
+ <parameter value="y_0=300090"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30792" name="Nord Sahara 1959 / Voirol Unifie Sud">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.3"/>
+ <parameter value="lat_0=33.3"/>
+ <parameter value="lon_0=2.7"/>
+ <parameter value="k_0=0.999625769"/>
+ <parameter value="x_0=500135"/>
+ <parameter value="y_0=300090"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="30800" name="RT38 2.5 gon W">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15.80827777777778"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31028" name="Yoff / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31121" name="Zanderij / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-265,120,-358,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31154" name="Zanderij / TM 54 NW">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-54"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-265,120,-358,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31170" name="Zanderij / Suriname Old TM">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.68333333333333"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-265,120,-358,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31171" name="Zanderij / Suriname TM">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.68333333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=-265,120,-358,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31265" name="MGI / 3-degree Gauss zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31266" name="MGI / 3-degree Gauss zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=18"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31267" name="MGI / 3-degree Gauss zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31268" name="MGI / 3-degree Gauss zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31275" name="MGI / Balkans zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31276" name="MGI / Balkans zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=18"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=6500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31277" name="MGI / Balkans zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31278" name="MGI / Balkans zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=21"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=7500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31279" name="MGI / Balkans zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=24"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=8500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31281" name="MGI (Ferro) / Austria West Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=10.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31282" name="MGI (Ferro) / Austria Central Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31283" name="MGI (Ferro) / Austria East Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=16.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31284" name="MGI / M28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=10.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31285" name="MGI / M31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=450000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31286" name="MGI / M34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=16.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=750000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31287" name="MGI / Austria Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=47.5"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31291" name="MGI (Ferro) / Austria West Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=10.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31292" name="MGI (Ferro) / Austria Central Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31293" name="MGI (Ferro) / Austria East Zone">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=16.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="pm=ferro"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31294" name="MGI / M28">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=10.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31295" name="MGI / M31">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=450000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31296" name="MGI / M34">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=16.33333333333333"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=750000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31297" name="MGI / Austria Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=47.5"/>
+ <parameter value="lon_0=13.33333333333333"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=400000"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31300" name="Belge 1972 / Belge Lambert 72">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49.83333333333334"/>
+ <parameter value="lat_2=51.16666666666666"/>
+ <parameter value="lat_0=90"/>
+ <parameter value="lon_0=4.356939722222222"/>
+ <parameter value="x_0=150000.01256"/>
+ <parameter value="y_0=5400088.4378"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31370" name="Belge 1972 / Belgian Lambert 72">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=51.16666723333333"/>
+ <parameter value="lat_2=49.8333339"/>
+ <parameter value="lat_0=90"/>
+ <parameter value="lon_0=4.367486666666666"/>
+ <parameter value="x_0=150000.013"/>
+ <parameter value="y_0=5400088.438"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31461" name="DHDN / 3-degree Gauss zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=3"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31462" name="DHDN / 3-degree Gauss zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=6"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31463" name="DHDN / 3-degree Gauss zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31464" name="DHDN / 3-degree Gauss zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31465" name="DHDN / 3-degree Gauss zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31466" name="DHDN / Gauss-Kruger zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=6"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31467" name="DHDN / Gauss-Kruger zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=9"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31468" name="DHDN / Gauss-Kruger zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=12"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=4500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31469" name="DHDN / Gauss-Kruger zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=15"/>
+ <parameter value="k=1.000000"/>
+ <parameter value="x_0=5500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=bessel"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31528" name="Conakry 1905 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-23,259,-9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31529" name="Conakry 1905 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="a=6378249.2"/>
+ <parameter value="b=6356515"/>
+ <parameter value="towgs84=-23,259,-9,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31600" name="Dealul Piscului 1933/ Stereo 33">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=45.9"/>
+ <parameter value="lon_0=25.39246588888889"/>
+ <parameter value="k=0.999667"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=intl"/>
+ <parameter value="towgs84=103.25,-100.4,-307.19,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31700" name="Dealul Piscului 1970/ Stereo 70">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=46"/>
+ <parameter value="lon_0=25"/>
+ <parameter value="k=0.999750"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=500000"/>
+ <parameter value="ellps=krass"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31838" name="NGN / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31839" name="NGN / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31900" name="KUDAMS / KTM">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=48"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31986" name="SIRGAS / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31987" name="SIRGAS / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31988" name="SIRGAS / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31989" name="SIRGAS / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31990" name="SIRGAS / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31991" name="SIRGAS / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31992" name="SIRGAS / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31993" name="SIRGAS / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31994" name="SIRGAS / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31995" name="SIRGAS / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31996" name="SIRGAS / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31997" name="SIRGAS / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31998" name="SIRGAS / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="31999" name="SIRGAS / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32000" name="SIRGAS / UTM zone 25S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="south"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="towgs84=0,0,0,0,0,0,0"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32001" name="NAD27 / Montana North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.71666666666667"/>
+ <parameter value="lat_2=47.85"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32002" name="NAD27 / Montana Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.88333333333333"/>
+ <parameter value="lat_2=46.45"/>
+ <parameter value="lat_0=45.83333333333334"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32003" name="NAD27 / Montana South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.4"/>
+ <parameter value="lat_2=44.86666666666667"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32005" name="NAD27 / Nebraska North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.85"/>
+ <parameter value="lat_2=42.81666666666667"/>
+ <parameter value="lat_0=41.33333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32006" name="NAD27 / Nebraska South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.28333333333333"/>
+ <parameter value="lat_2=41.71666666666667"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-99.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32007" name="NAD27 / Nevada East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-115.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32008" name="NAD27 / Nevada Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-116.6666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32009" name="NAD27 / Nevada West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-118.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32010" name="NAD27 / New Hampshire">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-71.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32011" name="NAD27 / New Jersey">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.66666666666667"/>
+ <parameter value="k=0.999975"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32012" name="NAD27 / New Mexico East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-104.3333333333333"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32013" name="NAD27 / New Mexico Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-106.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32014" name="NAD27 / New Mexico West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-107.8333333333333"/>
+ <parameter value="k=0.999917"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32015" name="NAD27 / New York East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-74.33333333333333"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32016" name="NAD27 / New York Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-76.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32017" name="NAD27 / New York West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-78.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32018" name="NAD27 / New York Long Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.03333333333333"/>
+ <parameter value="lat_2=40.66666666666666"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-74"/>
+ <parameter value="x_0=304800.6096012192"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32019" name="NAD27 / North Carolina">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.33333333333334"/>
+ <parameter value="lat_2=36.16666666666666"/>
+ <parameter value="lat_0=33.75"/>
+ <parameter value="lon_0=-79"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32020" name="NAD27 / North Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.43333333333333"/>
+ <parameter value="lat_2=48.73333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32021" name="NAD27 / North Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.18333333333333"/>
+ <parameter value="lat_2=47.48333333333333"/>
+ <parameter value="lat_0=45.66666666666666"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32022" name="NAD27 / Ohio North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.43333333333333"/>
+ <parameter value="lat_2=41.7"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32023" name="NAD27 / Ohio South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.73333333333333"/>
+ <parameter value="lat_2=40.03333333333333"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32024" name="NAD27 / Oklahoma North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.56666666666667"/>
+ <parameter value="lat_2=36.76666666666667"/>
+ <parameter value="lat_0=35"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32025" name="NAD27 / Oklahoma South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.93333333333333"/>
+ <parameter value="lat_2=35.23333333333333"/>
+ <parameter value="lat_0=33.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32026" name="NAD27 / Oregon North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.33333333333334"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32027" name="NAD27 / Oregon South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.33333333333334"/>
+ <parameter value="lat_2=44"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32028" name="NAD27 / Pennsylvania North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.88333333333333"/>
+ <parameter value="lat_2=41.95"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32029" name="NAD27 / Pennsylvania South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.93333333333333"/>
+ <parameter value="lat_2=40.8"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32030" name="NAD27 / Rhode Island">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.08333333333334"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="k=0.999994"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32031" name="NAD27 / South Carolina North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.76666666666667"/>
+ <parameter value="lat_2=34.96666666666667"/>
+ <parameter value="lat_0=33"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32033" name="NAD27 / South Carolina South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.33333333333334"/>
+ <parameter value="lat_2=33.66666666666666"/>
+ <parameter value="lat_0=31.83333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32034" name="NAD27 / South Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.41666666666666"/>
+ <parameter value="lat_2=45.68333333333333"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32035" name="NAD27 / South Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.83333333333334"/>
+ <parameter value="lat_2=44.4"/>
+ <parameter value="lat_0=42.33333333333334"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32036" name="NAD27 / Tennessee">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.25"/>
+ <parameter value="lat_2=36.41666666666666"/>
+ <parameter value="lat_0=34.66666666666666"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=30480.06096012192"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32037" name="NAD27 / Texas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.65"/>
+ <parameter value="lat_2=36.18333333333333"/>
+ <parameter value="lat_0=34"/>
+ <parameter value="lon_0=-101.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32038" name="NAD27 / Texas North Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=32.13333333333333"/>
+ <parameter value="lat_2=33.96666666666667"/>
+ <parameter value="lat_0=31.66666666666667"/>
+ <parameter value="lon_0=-97.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32039" name="NAD27 / Texas Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.11666666666667"/>
+ <parameter value="lat_2=31.88333333333333"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32040" name="NAD27 / Texas South Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=28.38333333333333"/>
+ <parameter value="lat_2=30.28333333333333"/>
+ <parameter value="lat_0=27.83333333333333"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32041" name="NAD27 / Texas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=26.16666666666667"/>
+ <parameter value="lat_2=27.83333333333333"/>
+ <parameter value="lat_0=25.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32042" name="NAD27 / Utah North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.71666666666667"/>
+ <parameter value="lat_2=41.78333333333333"/>
+ <parameter value="lat_0=40.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32043" name="NAD27 / Utah Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.01666666666667"/>
+ <parameter value="lat_2=40.65"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32044" name="NAD27 / Utah South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.21666666666667"/>
+ <parameter value="lat_2=38.35"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32045" name="NAD27 / Vermont">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-72.5"/>
+ <parameter value="k=0.999964"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32046" name="NAD27 / Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.03333333333333"/>
+ <parameter value="lat_2=39.2"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32047" name="NAD27 / Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.76666666666667"/>
+ <parameter value="lat_2=37.96666666666667"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32048" name="NAD27 / Washington North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.5"/>
+ <parameter value="lat_2=48.73333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-120.8333333333333"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32049" name="NAD27 / Washington South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.83333333333334"/>
+ <parameter value="lat_2=47.33333333333334"/>
+ <parameter value="lat_0=45.33333333333334"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32050" name="NAD27 / West Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39"/>
+ <parameter value="lat_2=40.25"/>
+ <parameter value="lat_0=38.5"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32051" name="NAD27 / West Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.48333333333333"/>
+ <parameter value="lat_2=38.88333333333333"/>
+ <parameter value="lat_0=37"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32052" name="NAD27 / Wisconsin North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.56666666666667"/>
+ <parameter value="lat_2=46.76666666666667"/>
+ <parameter value="lat_0=45.16666666666666"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32053" name="NAD27 / Wisconsin Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.25"/>
+ <parameter value="lat_2=45.5"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32054" name="NAD27 / Wisconsin South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=42.73333333333333"/>
+ <parameter value="lat_2=44.06666666666667"/>
+ <parameter value="lat_0=42"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=609601.2192024384"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32055" name="NAD27 / Wyoming East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.66666666666666"/>
+ <parameter value="lon_0=-105.1666666666667"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32056" name="NAD27 / Wyoming East Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.66666666666666"/>
+ <parameter value="lon_0=-107.3333333333333"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32057" name="NAD27 / Wyoming West Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.66666666666666"/>
+ <parameter value="lon_0=-108.75"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32058" name="NAD27 / Wyoming West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.66666666666666"/>
+ <parameter value="lon_0=-110.0833333333333"/>
+ <parameter value="k=0.999941"/>
+ <parameter value="x_0=152400.3048006096"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32061" name="NAD27 / Guatemala Norte">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=16.81666666666667"/>
+ <parameter value="lat_0=16.81666666666667"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k_0=0.99992226"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=292209.579"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32062" name="NAD27 / Guatemala Sur">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=14.9"/>
+ <parameter value="lat_0=14.9"/>
+ <parameter value="lon_0=-90.33333333333333"/>
+ <parameter value="k_0=0.99989906"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=325992.681"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32064" name="NAD27 / BLM 14N (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32065" name="NAD27 / BLM 15N (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-93"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32066" name="NAD27 / BLM 16N (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32067" name="NAD27 / BLM 17N (ftUS)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32074" name="NAD27 / BLM 14N (feet)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32075" name="NAD27 / BLM 15N (feet)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-93"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32076" name="NAD27 / BLM 16N (feet)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32077" name="NAD27 / BLM 17N (feet)">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000.001016002"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="to_meter=0.3048006096012192"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32081" name="NAD27 / MTM zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-53"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32082" name="NAD27 / MTM zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-56"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32083" name="NAD27 / MTM zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-58.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32084" name="NAD27 / MTM zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32085" name="NAD27 / MTM zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32086" name="NAD27 / MTM zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-67.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32098" name="NAD27 / Quebec Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=60"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="datum=NAD27"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32100" name="NAD83 / Montana">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=49"/>
+ <parameter value="lat_2=45"/>
+ <parameter value="lat_0=44.25"/>
+ <parameter value="lon_0=-109.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32104" name="NAD83 / Nebraska">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=43"/>
+ <parameter value="lat_2=40"/>
+ <parameter value="lat_0=39.83333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32107" name="NAD83 / Nevada East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-115.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=8000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32108" name="NAD83 / Nevada Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-116.6666666666667"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=6000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32109" name="NAD83 / Nevada West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=34.75"/>
+ <parameter value="lon_0=-118.5833333333333"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=4000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32110" name="NAD83 / New Hampshire">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-71.66666666666667"/>
+ <parameter value="k=0.999967"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32111" name="NAD83 / New Jersey">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32112" name="NAD83 / New Mexico East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-104.3333333333333"/>
+ <parameter value="k=0.999909"/>
+ <parameter value="x_0=165000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32113" name="NAD83 / New Mexico Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-106.25"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32114" name="NAD83 / New Mexico West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=31"/>
+ <parameter value="lon_0=-107.8333333333333"/>
+ <parameter value="k=0.999917"/>
+ <parameter value="x_0=830000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32115" name="NAD83 / New York East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=38.83333333333334"/>
+ <parameter value="lon_0=-74.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=150000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32116" name="NAD83 / New York Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-76.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=250000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32117" name="NAD83 / New York West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40"/>
+ <parameter value="lon_0=-78.58333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=350000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32118" name="NAD83 / New York Long Island">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.03333333333333"/>
+ <parameter value="lat_2=40.66666666666666"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-74"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32119" name="NAD83 / North Carolina">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.16666666666666"/>
+ <parameter value="lat_2=34.33333333333334"/>
+ <parameter value="lat_0=33.75"/>
+ <parameter value="lon_0=-79"/>
+ <parameter value="x_0=609601.22"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32120" name="NAD83 / North Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.43333333333333"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32121" name="NAD83 / North Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.48333333333333"/>
+ <parameter value="lat_2=46.18333333333333"/>
+ <parameter value="lat_0=45.66666666666666"/>
+ <parameter value="lon_0=-100.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32122" name="NAD83 / Ohio North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.7"/>
+ <parameter value="lat_2=40.43333333333333"/>
+ <parameter value="lat_0=39.66666666666666"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32123" name="NAD83 / Ohio South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.03333333333333"/>
+ <parameter value="lat_2=38.73333333333333"/>
+ <parameter value="lat_0=38"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32124" name="NAD83 / Oklahoma North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.76666666666667"/>
+ <parameter value="lat_2=35.56666666666667"/>
+ <parameter value="lat_0=35"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32125" name="NAD83 / Oklahoma South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=35.23333333333333"/>
+ <parameter value="lat_2=33.93333333333333"/>
+ <parameter value="lat_0=33.33333333333334"/>
+ <parameter value="lon_0=-98"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32126" name="NAD83 / Oregon North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46"/>
+ <parameter value="lat_2=44.33333333333334"/>
+ <parameter value="lat_0=43.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=2500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32127" name="NAD83 / Oregon South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44"/>
+ <parameter value="lat_2=42.33333333333334"/>
+ <parameter value="lat_0=41.66666666666666"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=1500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32128" name="NAD83 / Pennsylvania North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.95"/>
+ <parameter value="lat_2=40.88333333333333"/>
+ <parameter value="lat_0=40.16666666666666"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32129" name="NAD83 / Pennsylvania South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.96666666666667"/>
+ <parameter value="lat_2=39.93333333333333"/>
+ <parameter value="lat_0=39.33333333333334"/>
+ <parameter value="lon_0=-77.75"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32130" name="NAD83 / Rhode Island">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=41.08333333333334"/>
+ <parameter value="lon_0=-71.5"/>
+ <parameter value="k=0.999994"/>
+ <parameter value="x_0=100000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32133" name="NAD83 / South Carolina">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=34.83333333333334"/>
+ <parameter value="lat_2=32.5"/>
+ <parameter value="lat_0=31.83333333333333"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=609600"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32134" name="NAD83 / South Dakota North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.68333333333333"/>
+ <parameter value="lat_2=44.41666666666666"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-100"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32135" name="NAD83 / South Dakota South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.4"/>
+ <parameter value="lat_2=42.83333333333334"/>
+ <parameter value="lat_0=42.33333333333334"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32136" name="NAD83 / Tennessee">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.41666666666666"/>
+ <parameter value="lat_2=35.25"/>
+ <parameter value="lat_0=34.33333333333334"/>
+ <parameter value="lon_0=-86"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32137" name="NAD83 / Texas North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=36.18333333333333"/>
+ <parameter value="lat_2=34.65"/>
+ <parameter value="lat_0=34"/>
+ <parameter value="lon_0=-101.5"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32138" name="NAD83 / Texas North Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=33.96666666666667"/>
+ <parameter value="lat_2=32.13333333333333"/>
+ <parameter value="lat_0=31.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32139" name="NAD83 / Texas Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=31.88333333333333"/>
+ <parameter value="lat_2=30.11666666666667"/>
+ <parameter value="lat_0=29.66666666666667"/>
+ <parameter value="lon_0=-100.3333333333333"/>
+ <parameter value="x_0=700000"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32140" name="NAD83 / Texas South Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=30.28333333333333"/>
+ <parameter value="lat_2=28.38333333333333"/>
+ <parameter value="lat_0=27.83333333333333"/>
+ <parameter value="lon_0=-99"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=4000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32141" name="NAD83 / Texas South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=27.83333333333333"/>
+ <parameter value="lat_2=26.16666666666667"/>
+ <parameter value="lat_0=25.66666666666667"/>
+ <parameter value="lon_0=-98.5"/>
+ <parameter value="x_0=300000"/>
+ <parameter value="y_0=5000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32142" name="NAD83 / Utah North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=41.78333333333333"/>
+ <parameter value="lat_2=40.71666666666667"/>
+ <parameter value="lat_0=40.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32143" name="NAD83 / Utah Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.65"/>
+ <parameter value="lat_2=39.01666666666667"/>
+ <parameter value="lat_0=38.33333333333334"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32144" name="NAD83 / Utah South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.35"/>
+ <parameter value="lat_2=37.21666666666667"/>
+ <parameter value="lat_0=36.66666666666666"/>
+ <parameter value="lon_0=-111.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=3000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32145" name="NAD83 / Vermont">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=42.5"/>
+ <parameter value="lon_0=-72.5"/>
+ <parameter value="k=0.999964"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32146" name="NAD83 / Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=39.2"/>
+ <parameter value="lat_2=38.03333333333333"/>
+ <parameter value="lat_0=37.66666666666666"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32147" name="NAD83 / Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=37.96666666666667"/>
+ <parameter value="lat_2=36.76666666666667"/>
+ <parameter value="lat_0=36.33333333333334"/>
+ <parameter value="lon_0=-78.5"/>
+ <parameter value="x_0=3500000"/>
+ <parameter value="y_0=1000000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32148" name="NAD83 / Washington North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=48.73333333333333"/>
+ <parameter value="lat_2=47.5"/>
+ <parameter value="lat_0=47"/>
+ <parameter value="lon_0=-120.8333333333333"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32149" name="NAD83 / Washington South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=47.33333333333334"/>
+ <parameter value="lat_2=45.83333333333334"/>
+ <parameter value="lat_0=45.33333333333334"/>
+ <parameter value="lon_0=-120.5"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32150" name="NAD83 / West Virginia North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=40.25"/>
+ <parameter value="lat_2=39"/>
+ <parameter value="lat_0=38.5"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32151" name="NAD83 / West Virginia South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=38.88333333333333"/>
+ <parameter value="lat_2=37.48333333333333"/>
+ <parameter value="lat_0=37"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32152" name="NAD83 / Wisconsin North">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=46.76666666666667"/>
+ <parameter value="lat_2=45.56666666666667"/>
+ <parameter value="lat_0=45.16666666666666"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32153" name="NAD83 / Wisconsin Central">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=45.5"/>
+ <parameter value="lat_2=44.25"/>
+ <parameter value="lat_0=43.83333333333334"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32154" name="NAD83 / Wisconsin South">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=44.06666666666667"/>
+ <parameter value="lat_2=42.73333333333333"/>
+ <parameter value="lat_0=42"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32155" name="NAD83 / Wyoming East">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-105.1666666666667"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32156" name="NAD83 / Wyoming East Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-107.3333333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=400000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32157" name="NAD83 / Wyoming West Central">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-108.75"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=600000"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32158" name="NAD83 / Wyoming West">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=40.5"/>
+ <parameter value="lon_0=-110.0833333333333"/>
+ <parameter value="k=0.999938"/>
+ <parameter value="x_0=800000"/>
+ <parameter value="y_0=100000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32161" name="NAD83 / Puerto Rico & Virgin Is.">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=18.43333333333333"/>
+ <parameter value="lat_2=18.03333333333333"/>
+ <parameter value="lat_0=17.83333333333333"/>
+ <parameter value="lon_0=-66.43333333333334"/>
+ <parameter value="x_0=200000"/>
+ <parameter value="y_0=200000"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32180" name="NAD83 / SCoPQ zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-55.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32181" name="NAD83 / MTM zone 1">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-53"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32182" name="NAD83 / MTM zone 2">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-56"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32183" name="NAD83 / MTM zone 3">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-58.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32184" name="NAD83 / MTM zone 4">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-61.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32185" name="NAD83 / MTM zone 5">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-64.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32186" name="NAD83 / MTM zone 6">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-67.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32187" name="NAD83 / MTM zone 7">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-70.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32188" name="NAD83 / MTM zone 8">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-73.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32189" name="NAD83 / MTM zone 9">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-76.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32190" name="NAD83 / MTM zone 10">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-79.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32191" name="NAD83 / MTM zone 11">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-82.5"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32192" name="NAD83 / MTM zone 12">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-81"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32193" name="NAD83 / MTM zone 13">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-84"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32194" name="NAD83 / MTM zone 14">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-87"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32195" name="NAD83 / MTM zone 15">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-90"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32196" name="NAD83 / MTM zone 16">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-93"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32197" name="NAD83 / MTM zone 17">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=-96"/>
+ <parameter value="k=0.999900"/>
+ <parameter value="x_0=304800"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32198" name="NAD83 / Quebec Lambert">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=60"/>
+ <parameter value="lat_2=46"/>
+ <parameter value="lat_0=44"/>
+ <parameter value="lon_0=-68.5"/>
+ <parameter value="x_0=0"/>
+ <parameter value="y_0=0"/>
+ <parameter value="ellps=GRS80"/>
+ <parameter value="datum=NAD83"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32201" name="WGS 72 / UTM zone 1N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32202" name="WGS 72 / UTM zone 2N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32203" name="WGS 72 / UTM zone 3N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32204" name="WGS 72 / UTM zone 4N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32205" name="WGS 72 / UTM zone 5N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32206" name="WGS 72 / UTM zone 6N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32207" name="WGS 72 / UTM zone 7N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32208" name="WGS 72 / UTM zone 8N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32209" name="WGS 72 / UTM zone 9N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32210" name="WGS 72 / UTM zone 10N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32211" name="WGS 72 / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32212" name="WGS 72 / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32213" name="WGS 72 / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32214" name="WGS 72 / UTM zone 14N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32215" name="WGS 72 / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32216" name="WGS 72 / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32217" name="WGS 72 / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32218" name="WGS 72 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32219" name="WGS 72 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32220" name="WGS 72 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32221" name="WGS 72 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32222" name="WGS 72 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32223" name="WGS 72 / UTM zone 23N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32224" name="WGS 72 / UTM zone 24N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32225" name="WGS 72 / UTM zone 25N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32226" name="WGS 72 / UTM zone 26N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32227" name="WGS 72 / UTM zone 27N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32228" name="WGS 72 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32229" name="WGS 72 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32230" name="WGS 72 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32231" name="WGS 72 / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32232" name="WGS 72 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32233" name="WGS 72 / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32234" name="WGS 72 / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32235" name="WGS 72 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32236" name="WGS 72 / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32237" name="WGS 72 / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32238" name="WGS 72 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32239" name="WGS 72 / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32240" name="WGS 72 / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32241" name="WGS 72 / UTM zone 41N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32242" name="WGS 72 / UTM zone 42N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32243" name="WGS 72 / UTM zone 43N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32244" name="WGS 72 / UTM zone 44N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32245" name="WGS 72 / UTM zone 45N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32246" name="WGS 72 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32247" name="WGS 72 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32248" name="WGS 72 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32249" name="WGS 72 / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32250" name="WGS 72 / UTM zone 50N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32251" name="WGS 72 / UTM zone 51N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32252" name="WGS 72 / UTM zone 52N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32253" name="WGS 72 / UTM zone 53N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32254" name="WGS 72 / UTM zone 54N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32255" name="WGS 72 / UTM zone 55N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32256" name="WGS 72 / UTM zone 56N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32257" name="WGS 72 / UTM zone 57N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32258" name="WGS 72 / UTM zone 58N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32259" name="WGS 72 / UTM zone 59N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32260" name="WGS 72 / UTM zone 60N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32301" name="WGS 72 / UTM zone 1S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32302" name="WGS 72 / UTM zone 2S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32303" name="WGS 72 / UTM zone 3S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32304" name="WGS 72 / UTM zone 4S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32305" name="WGS 72 / UTM zone 5S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32306" name="WGS 72 / UTM zone 6S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32307" name="WGS 72 / UTM zone 7S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32308" name="WGS 72 / UTM zone 8S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32309" name="WGS 72 / UTM zone 9S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32310" name="WGS 72 / UTM zone 10S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32311" name="WGS 72 / UTM zone 11S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32312" name="WGS 72 / UTM zone 12S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32313" name="WGS 72 / UTM zone 13S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32314" name="WGS 72 / UTM zone 14S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32315" name="WGS 72 / UTM zone 15S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32316" name="WGS 72 / UTM zone 16S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32317" name="WGS 72 / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32318" name="WGS 72 / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32319" name="WGS 72 / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32320" name="WGS 72 / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32321" name="WGS 72 / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32322" name="WGS 72 / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32323" name="WGS 72 / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32324" name="WGS 72 / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32325" name="WGS 72 / UTM zone 25S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32326" name="WGS 72 / UTM zone 26S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32327" name="WGS 72 / UTM zone 27S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32328" name="WGS 72 / UTM zone 28S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32329" name="WGS 72 / UTM zone 29S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32330" name="WGS 72 / UTM zone 30S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32331" name="WGS 72 / UTM zone 31S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32332" name="WGS 72 / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32333" name="WGS 72 / UTM zone 33S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32334" name="WGS 72 / UTM zone 34S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32335" name="WGS 72 / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32336" name="WGS 72 / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32337" name="WGS 72 / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32338" name="WGS 72 / UTM zone 38S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32339" name="WGS 72 / UTM zone 39S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32340" name="WGS 72 / UTM zone 40S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32341" name="WGS 72 / UTM zone 41S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32342" name="WGS 72 / UTM zone 42S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32343" name="WGS 72 / UTM zone 43S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32344" name="WGS 72 / UTM zone 44S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32345" name="WGS 72 / UTM zone 45S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32346" name="WGS 72 / UTM zone 46S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32347" name="WGS 72 / UTM zone 47S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32348" name="WGS 72 / UTM zone 48S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32349" name="WGS 72 / UTM zone 49S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32350" name="WGS 72 / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32351" name="WGS 72 / UTM zone 51S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32352" name="WGS 72 / UTM zone 52S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32353" name="WGS 72 / UTM zone 53S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32354" name="WGS 72 / UTM zone 54S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32355" name="WGS 72 / UTM zone 55S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32356" name="WGS 72 / UTM zone 56S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32357" name="WGS 72 / UTM zone 57S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32358" name="WGS 72 / UTM zone 58S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32359" name="WGS 72 / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32360" name="WGS 72 / UTM zone 60S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32401" name="WGS 72BE / UTM zone 1N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32402" name="WGS 72BE / UTM zone 2N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32403" name="WGS 72BE / UTM zone 3N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32404" name="WGS 72BE / UTM zone 4N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32405" name="WGS 72BE / UTM zone 5N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32406" name="WGS 72BE / UTM zone 6N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32407" name="WGS 72BE / UTM zone 7N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32408" name="WGS 72BE / UTM zone 8N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32409" name="WGS 72BE / UTM zone 9N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32410" name="WGS 72BE / UTM zone 10N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32411" name="WGS 72BE / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32412" name="WGS 72BE / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32413" name="WGS 72BE / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32414" name="WGS 72BE / UTM zone 14N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32415" name="WGS 72BE / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32416" name="WGS 72BE / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32417" name="WGS 72BE / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32418" name="WGS 72BE / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32419" name="WGS 72BE / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32420" name="WGS 72BE / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32421" name="WGS 72BE / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32422" name="WGS 72BE / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32423" name="WGS 72BE / UTM zone 23N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32424" name="WGS 72BE / UTM zone 24N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32425" name="WGS 72BE / UTM zone 25N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32426" name="WGS 72BE / UTM zone 26N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32427" name="WGS 72BE / UTM zone 27N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32428" name="WGS 72BE / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32429" name="WGS 72BE / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32430" name="WGS 72BE / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32431" name="WGS 72BE / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32432" name="WGS 72BE / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32433" name="WGS 72BE / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32434" name="WGS 72BE / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32435" name="WGS 72BE / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32436" name="WGS 72BE / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32437" name="WGS 72BE / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32438" name="WGS 72BE / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32439" name="WGS 72BE / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32440" name="WGS 72BE / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32441" name="WGS 72BE / UTM zone 41N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32442" name="WGS 72BE / UTM zone 42N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32443" name="WGS 72BE / UTM zone 43N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32444" name="WGS 72BE / UTM zone 44N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32445" name="WGS 72BE / UTM zone 45N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32446" name="WGS 72BE / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32447" name="WGS 72BE / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32448" name="WGS 72BE / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32449" name="WGS 72BE / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32450" name="WGS 72BE / UTM zone 50N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32451" name="WGS 72BE / UTM zone 51N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32452" name="WGS 72BE / UTM zone 52N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32453" name="WGS 72BE / UTM zone 53N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32454" name="WGS 72BE / UTM zone 54N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32455" name="WGS 72BE / UTM zone 55N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32456" name="WGS 72BE / UTM zone 56N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32457" name="WGS 72BE / UTM zone 57N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32458" name="WGS 72BE / UTM zone 58N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32459" name="WGS 72BE / UTM zone 59N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32460" name="WGS 72BE / UTM zone 60N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32501" name="WGS 72BE / UTM zone 1S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32502" name="WGS 72BE / UTM zone 2S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32503" name="WGS 72BE / UTM zone 3S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32504" name="WGS 72BE / UTM zone 4S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32505" name="WGS 72BE / UTM zone 5S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32506" name="WGS 72BE / UTM zone 6S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32507" name="WGS 72BE / UTM zone 7S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32508" name="WGS 72BE / UTM zone 8S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32509" name="WGS 72BE / UTM zone 9S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32510" name="WGS 72BE / UTM zone 10S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32511" name="WGS 72BE / UTM zone 11S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32512" name="WGS 72BE / UTM zone 12S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32513" name="WGS 72BE / UTM zone 13S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32514" name="WGS 72BE / UTM zone 14S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32515" name="WGS 72BE / UTM zone 15S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32516" name="WGS 72BE / UTM zone 16S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32517" name="WGS 72BE / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32518" name="WGS 72BE / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32519" name="WGS 72BE / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32520" name="WGS 72BE / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32521" name="WGS 72BE / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32522" name="WGS 72BE / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32523" name="WGS 72BE / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32524" name="WGS 72BE / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32525" name="WGS 72BE / UTM zone 25S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32526" name="WGS 72BE / UTM zone 26S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32527" name="WGS 72BE / UTM zone 27S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32528" name="WGS 72BE / UTM zone 28S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32529" name="WGS 72BE / UTM zone 29S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32530" name="WGS 72BE / UTM zone 30S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32531" name="WGS 72BE / UTM zone 31S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32532" name="WGS 72BE / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32533" name="WGS 72BE / UTM zone 33S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32534" name="WGS 72BE / UTM zone 34S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32535" name="WGS 72BE / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32536" name="WGS 72BE / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32537" name="WGS 72BE / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32538" name="WGS 72BE / UTM zone 38S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32539" name="WGS 72BE / UTM zone 39S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32540" name="WGS 72BE / UTM zone 40S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32541" name="WGS 72BE / UTM zone 41S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32542" name="WGS 72BE / UTM zone 42S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32543" name="WGS 72BE / UTM zone 43S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32544" name="WGS 72BE / UTM zone 44S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32545" name="WGS 72BE / UTM zone 45S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32546" name="WGS 72BE / UTM zone 46S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32547" name="WGS 72BE / UTM zone 47S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32548" name="WGS 72BE / UTM zone 48S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32549" name="WGS 72BE / UTM zone 49S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32550" name="WGS 72BE / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32551" name="WGS 72BE / UTM zone 51S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32552" name="WGS 72BE / UTM zone 52S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32553" name="WGS 72BE / UTM zone 53S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32554" name="WGS 72BE / UTM zone 54S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32555" name="WGS 72BE / UTM zone 55S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32556" name="WGS 72BE / UTM zone 56S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32557" name="WGS 72BE / UTM zone 57S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32558" name="WGS 72BE / UTM zone 58S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32559" name="WGS 72BE / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32560" name="WGS 72BE / UTM zone 60S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS72"/>
+ <parameter value="towgs84=0,0,1.9,0,0,0.814,-0.38"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32601" name="WGS 84 / UTM zone 1N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32602" name="WGS 84 / UTM zone 2N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32603" name="WGS 84 / UTM zone 3N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32604" name="WGS 84 / UTM zone 4N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32605" name="WGS 84 / UTM zone 5N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32606" name="WGS 84 / UTM zone 6N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32607" name="WGS 84 / UTM zone 7N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32608" name="WGS 84 / UTM zone 8N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32609" name="WGS 84 / UTM zone 9N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32610" name="WGS 84 / UTM zone 10N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32611" name="WGS 84 / UTM zone 11N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32612" name="WGS 84 / UTM zone 12N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32613" name="WGS 84 / UTM zone 13N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32614" name="WGS 84 / UTM zone 14N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32615" name="WGS 84 / UTM zone 15N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32616" name="WGS 84 / UTM zone 16N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32617" name="WGS 84 / UTM zone 17N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32618" name="WGS 84 / UTM zone 18N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32619" name="WGS 84 / UTM zone 19N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32620" name="WGS 84 / UTM zone 20N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32621" name="WGS 84 / UTM zone 21N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32622" name="WGS 84 / UTM zone 22N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32623" name="WGS 84 / UTM zone 23N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32624" name="WGS 84 / UTM zone 24N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32625" name="WGS 84 / UTM zone 25N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32626" name="WGS 84 / UTM zone 26N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32627" name="WGS 84 / UTM zone 27N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32628" name="WGS 84 / UTM zone 28N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32629" name="WGS 84 / UTM zone 29N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32630" name="WGS 84 / UTM zone 30N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32631" name="WGS 84 / UTM zone 31N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32632" name="WGS 84 / UTM zone 32N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32633" name="WGS 84 / UTM zone 33N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32634" name="WGS 84 / UTM zone 34N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32635" name="WGS 84 / UTM zone 35N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32636" name="WGS 84 / UTM zone 36N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32637" name="WGS 84 / UTM zone 37N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32638" name="WGS 84 / UTM zone 38N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32639" name="WGS 84 / UTM zone 39N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32640" name="WGS 84 / UTM zone 40N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32641" name="WGS 84 / UTM zone 41N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32642" name="WGS 84 / UTM zone 42N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32643" name="WGS 84 / UTM zone 43N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32644" name="WGS 84 / UTM zone 44N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32645" name="WGS 84 / UTM zone 45N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32646" name="WGS 84 / UTM zone 46N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32647" name="WGS 84 / UTM zone 47N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32648" name="WGS 84 / UTM zone 48N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32649" name="WGS 84 / UTM zone 49N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32650" name="WGS 84 / UTM zone 50N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32651" name="WGS 84 / UTM zone 51N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32652" name="WGS 84 / UTM zone 52N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32653" name="WGS 84 / UTM zone 53N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32654" name="WGS 84 / UTM zone 54N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32655" name="WGS 84 / UTM zone 55N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32656" name="WGS 84 / UTM zone 56N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32657" name="WGS 84 / UTM zone 57N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32658" name="WGS 84 / UTM zone 58N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32659" name="WGS 84 / UTM zone 59N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32660" name="WGS 84 / UTM zone 60N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32661" name="WGS 84 / UPS North">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=90"/>
+ <parameter value="lat_ts=90"/>
+ <parameter value="lon_0=0"/>
+ <parameter value="k=0.994"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32701" name="WGS 84 / UTM zone 1S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=1"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32702" name="WGS 84 / UTM zone 2S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=2"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32703" name="WGS 84 / UTM zone 3S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=3"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32704" name="WGS 84 / UTM zone 4S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=4"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32705" name="WGS 84 / UTM zone 5S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=5"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32706" name="WGS 84 / UTM zone 6S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=6"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32707" name="WGS 84 / UTM zone 7S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=7"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32708" name="WGS 84 / UTM zone 8S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=8"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32709" name="WGS 84 / UTM zone 9S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=9"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32710" name="WGS 84 / UTM zone 10S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=10"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32711" name="WGS 84 / UTM zone 11S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=11"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32712" name="WGS 84 / UTM zone 12S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=12"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32713" name="WGS 84 / UTM zone 13S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=13"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32714" name="WGS 84 / UTM zone 14S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=14"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32715" name="WGS 84 / UTM zone 15S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=15"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32716" name="WGS 84 / UTM zone 16S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=16"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32717" name="WGS 84 / UTM zone 17S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=17"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32718" name="WGS 84 / UTM zone 18S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=18"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32719" name="WGS 84 / UTM zone 19S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=19"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32720" name="WGS 84 / UTM zone 20S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=20"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32721" name="WGS 84 / UTM zone 21S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=21"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32722" name="WGS 84 / UTM zone 22S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=22"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32723" name="WGS 84 / UTM zone 23S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=23"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32724" name="WGS 84 / UTM zone 24S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=24"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32725" name="WGS 84 / UTM zone 25S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=25"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32726" name="WGS 84 / UTM zone 26S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=26"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32727" name="WGS 84 / UTM zone 27S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32728" name="WGS 84 / UTM zone 28S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=28"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32729" name="WGS 84 / UTM zone 29S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=29"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32730" name="WGS 84 / UTM zone 30S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=30"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32731" name="WGS 84 / UTM zone 31S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=31"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32732" name="WGS 84 / UTM zone 32S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=32"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32733" name="WGS 84 / UTM zone 33S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=33"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32734" name="WGS 84 / UTM zone 34S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=34"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32735" name="WGS 84 / UTM zone 35S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=35"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32736" name="WGS 84 / UTM zone 36S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=36"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32737" name="WGS 84 / UTM zone 37S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=37"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32738" name="WGS 84 / UTM zone 38S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=38"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32739" name="WGS 84 / UTM zone 39S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=39"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32740" name="WGS 84 / UTM zone 40S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=40"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32741" name="WGS 84 / UTM zone 41S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=41"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32742" name="WGS 84 / UTM zone 42S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=42"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32743" name="WGS 84 / UTM zone 43S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=43"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32744" name="WGS 84 / UTM zone 44S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=44"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32745" name="WGS 84 / UTM zone 45S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=45"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32746" name="WGS 84 / UTM zone 46S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=46"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32747" name="WGS 84 / UTM zone 47S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=47"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32748" name="WGS 84 / UTM zone 48S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=48"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32749" name="WGS 84 / UTM zone 49S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=49"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32750" name="WGS 84 / UTM zone 50S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=50"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32751" name="WGS 84 / UTM zone 51S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=51"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32752" name="WGS 84 / UTM zone 52S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=52"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32753" name="WGS 84 / UTM zone 53S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=53"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32754" name="WGS 84 / UTM zone 54S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=54"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32755" name="WGS 84 / UTM zone 55S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=55"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32756" name="WGS 84 / UTM zone 56S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=56"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32757" name="WGS 84 / UTM zone 57S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=57"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32758" name="WGS 84 / UTM zone 58S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=58"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32759" name="WGS 84 / UTM zone 59S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=59"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32760" name="WGS 84 / UTM zone 60S">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=60"/>
+ <parameter value="south"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32761" name="WGS 84 / UPS South">
+ <parameter value="proj=stere"/>
+ <parameter value="lat_0=-90"/>
+ <parameter value="lat_ts=-90"/>
+ <parameter value="lon_0=0"/>
+ <parameter value="k=0.994"/>
+ <parameter value="x_0=2000000"/>
+ <parameter value="y_0=2000000"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+ <projection epsg="32766" name="WGS 84 / TM 36 SE">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0"/>
+ <parameter value="lon_0=36"/>
+ <parameter value="k=0.999600"/>
+ <parameter value="x_0=500000"/>
+ <parameter value="y_0=10000000"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ <parameter value="no_defs"/>
+ </projection>
+</projectionlist>
Added: packages/thuban/branches/upstream/current/Resources/XML/projfile.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/projfile.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/projfile.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- projfile.dtd
+
+ Copyright (C) 2003 by Intevation GmbH
+ Authors:
+ Bernhard Herzog <bh at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+
+ $Revision: 1817 $
+ $Source$
+ $Id: projfile.dtd 1817 2003-10-13 15:54:02Z bh $
+-->
+
+<!-- a projfile is a list of projections. The projections are stored in
+ the same way as in a .thuban file
+ -->
+
+<!ELEMENT projectionlist (projection*)>
+
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA ""
+ epsg CDATA #IMPLIED >
+
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
Added: packages/thuban/branches/upstream/current/Resources/XML/thuban-0.8.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/thuban-0.8.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/thuban-0.8.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- thuban-0.8.dtd
+
+ Copyright (C) 2001, 2003 by Intevation GmbH
+ Authors:
+ Jan-Oliver Wagner <jan at intevation.de>
+ Bernhard Herzog <bh at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+-->
+
+<!-- a session contains zero or more datasources and and zero or more maps
+
+At some point, the namespace attribute will likely be used by Thuban to
+identify the version of the file format.
+-->
+
+<!ENTITY % shapesources "fileshapesource | derivedshapesource">
+<!ENTITY % tables "filetable | jointable">
+<!ELEMENT session ((%shapesources; | %tables; )*, map*)>
+<!ATTLIST session
+ title CDATA #REQUIRED
+ xmlns CDATA #IMPLIED
+>
+
+
+<!--
+ A fileshapesource is a source of shapes and perhaps attribute data
+ read from a file. The filetype attribute must be one of the
+ supported file types. Currently only "shapefile" is supported.
+ -->
+
+<!ELEMENT fileshapesource EMPTY>
+<!ATTLIST fileshapesource
+ id ID #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED
+>
+
+<!--
+ A derivedshapesource is a source of shapes and attribute data
+ derived from another shapesource for the shapes and a table for the
+ attribute data.
+ -->
+
+<!ELEMENT derivedshapesource EMPTY>
+<!ATTLIST derivedshapesource
+ id ID #REQUIRED
+ shapesource IDREF #REQUIRED
+ table IDREF #REQUIRED
+>
+
+
+<!-- a filetable points to the actual file that
+ contains the tabular data.
+
+ The filetype Attribute may be onve of "DBF" or "CSV"
+-->
+<!ELEMENT filetable EMPTY>
+<!ATTLIST filetable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED>
+
+<!--
+ A jointable is a table with the result of something equivalent to
+ this SQL Statement:
+
+ SELECT * FROM left JOIN right WHERE left.leftcolumn = right.rightcolumn;
+
+ The attributes left and right must be the ids of two tables defined
+ previously in the XML-Document file. leftcolumn and rightcolumn are
+ the column names to join on.
+-->
+<!ELEMENT jointable EMPTY>
+<!ATTLIST jointable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ left IDREF #REQUIRED
+ leftcolumn CDATA #REQUIRED
+ right IDREF #REQUIRED
+ rightcolumn CDATA #REQUIRED
+>
+
+<!-- A Map
+
+ A map consists of a number of layers
+ the projection refers to the projection
+ used to display the map. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed.
+-->
+<!ELEMENT map (projection?, (layer | rasterlayer)*, labellayer?)>
+<!ATTLIST map title CDATA #REQUIRED>
+
+<!-- a layer represents a set of geographic objects.
+ pointers to the actual data are stored.
+ The shapestore attributes contains the id of the data store
+ shown in the layer.
+ the projection refers to the projection
+ in which the data are stored. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed. Visibility is assumed true
+ unless otherwise specified.
+-->
+<!ELEMENT layer (projection?, classification?)>
+<!ATTLIST layer title CDATA #REQUIRED>
+<!ATTLIST layer shapestore IDREF #REQUIRED>
+<!ATTLIST layer visible (true|false) "true">
+<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ATTLIST layer fill CDATA "None">
+<!ATTLIST layer stroke CDATA "#000000">
+<!ATTLIST layer stroke_width CDATA "1">
+
+
+<!-- a rasterlayer represents an image that has some geographic data
+ associated with it. The filename points to the image used.
+-->
+<!ELEMENT rasterlayer (projection?, classification?)>
+<!ATTLIST rasterlayer
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ visible (true|false) "true">
+
+
+<!-- Classification data -->
+<!ELEMENT classification (clnull?, clpoint*, clrange*, clcont*)>
+<!ATTLIST classification field CDATA #REQUIRED>
+<!ATTLIST classification field_type CDATA #REQUIRED>
+
+<!ELEMENT clnull (cldata*)>
+<!ELEMENT clpoint (cldata*)>
+<!ELEMENT clrange (cldata*)>
+<!ELEMENT clcont (cldata*)>
+
+<!ATTLIST clnull label CDATA #IMPLIED>
+
+<!ATTLIST clpoint value CDATA #REQUIRED>
+<!ATTLIST clpoint label CDATA #IMPLIED>
+
+<!ATTLIST clrange min CDATA #IMPLIED>
+<!ATTLIST clrange max CDATA #IMPLIED>
+<!ATTLIST clrange range CDATA #IMPLIED>
+<!ATTLIST clrange label CDATA #IMPLIED>
+
+<!ATTLIST clcont rmin CDATA #REQUIRED>
+<!ATTLIST clcont rmax CDATA #REQUIRED>
+<!ATTLIST clcont dmin CDATA #REQUIRED>
+<!ATTLIST clcont dmax CDATA #REQUIRED>
+
+<!-- Visual appearance of the classification
+
+ the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ELEMENT cldata EMPTY>
+<!ATTLIST cldata
+ stroke CDATA #IMPLIED
+ stroke_width CDATA #IMPLIED
+ fill CDATA #IMPLIED
+>
+
+
+<!-- a projection has a number of parameters
+-->
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA "" >
+
+<!-- just a simple parameter consisting of a value
+-->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
+
+
+<!-- The label layer contains text labels -->
+<!ELEMENT labellayer (label*) >
+
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ text CDATA #REQUIRED
+ halign (left|center|right) #REQUIRED
+ valign (top|center|bottom) #REQUIRED>
Added: packages/thuban/branches/upstream/current/Resources/XML/thuban-0.9.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/thuban-0.9.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/thuban-0.9.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- thuban-0.9.dtd
+
+ Copyright (C) 2001, 2003 by Intevation GmbH
+ Authors:
+ Jan-Oliver Wagner <jan at intevation.de>
+ Bernhard Herzog <bh at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+-->
+
+<!-- a session contains zero or more database connections zero or more
+ datasources and and zero or more maps
+
+At some point, the namespace attribute will likely be used by Thuban to
+identify the version of the file format.
+-->
+
+<!ENTITY % shapesources "fileshapesource | derivedshapesource | dbshapesource">
+<!ENTITY % tables "filetable | jointable">
+<!ELEMENT session ((dbconnection | %shapesources; | %tables; )*, map*)>
+<!ATTLIST session
+ title CDATA #REQUIRED
+ xmlns CDATA #IMPLIED
+>
+
+
+<!--
+ A db connection represents the connection to a database.
+
+ Currently only connections to postgis databases are supported and
+ thus The dbtype attribute must be "postgis".
+-->
+
+<!ELEMENT dbconnection EMPTY>
+<!ATTLIST dbconnection
+ id ID #REQUIRED
+ dbtype CDATA #REQUIRED
+ dbname CDATA #REQUIRED
+ host CDATA ""
+ port CDATA ""
+ user CDATA ""
+>
+
+
+<!-- A dbshapesource represents a table with geometry data in a database
+
+ The dbconn attribute must be the id of a dbconnection element
+ occurring earlier in the document.
+-->
+
+<!ELEMENT dbshapesource EMPTY>
+<!ATTLIST dbshapesource
+ id ID #REQUIRED
+ dbconn IDREF #REQUIRED
+ tablename CDATA #REQUIRED
+>
+
+<!--
+ A fileshapesource is a source of shapes and perhaps attribute data
+ read from a file. The filetype attribute must be one of the
+ supported file types. Currently only "shapefile" is supported.
+ -->
+
+<!ELEMENT fileshapesource EMPTY>
+<!ATTLIST fileshapesource
+ id ID #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED
+>
+
+<!--
+ A derivedshapesource is a source of shapes and attribute data
+ derived from another shapesource for the shapes and a table for the
+ attribute data.
+ -->
+
+<!ELEMENT derivedshapesource EMPTY>
+<!ATTLIST derivedshapesource
+ id ID #REQUIRED
+ shapesource IDREF #REQUIRED
+ table IDREF #REQUIRED
+>
+
+
+<!-- a filetable points to the actual file that
+ contains the tabular data.
+
+ The filetype Attribute may be onve of "DBF" or "CSV"
+-->
+<!ELEMENT filetable EMPTY>
+<!ATTLIST filetable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED>
+
+<!--
+ A jointable is a table with the result of something equivalent to
+ this SQL Statement:
+
+ SELECT * FROM left JOIN right WHERE left.leftcolumn = right.rightcolumn;
+
+ The attributes left and right must be the ids of two tables defined
+ previously in the XML-Document file. leftcolumn and rightcolumn are
+ the column names to join on.
+
+ The jointype attribute should be either "INNER" or "LEFT OUTER".
+-->
+<!ELEMENT jointable EMPTY>
+<!ATTLIST jointable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ left IDREF #REQUIRED
+ leftcolumn CDATA #REQUIRED
+ right IDREF #REQUIRED
+ rightcolumn CDATA #REQUIRED
+ jointype CDATA #REQUIRED
+>
+
+<!-- A Map
+
+ A map consists of a number of layers
+ the projection refers to the projection
+ used to display the map. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed.
+-->
+<!ELEMENT map (projection?, (layer | rasterlayer)*, labellayer?)>
+<!ATTLIST map title CDATA #REQUIRED>
+
+<!-- a layer represents a set of geographic objects.
+ pointers to the actual data are stored.
+ The shapestore attributes contains the id of the data store
+ shown in the layer.
+ the projection refers to the projection
+ in which the data are stored. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed. Visibility is assumed true
+ unless otherwise specified.
+-->
+<!ELEMENT layer (projection?, classification?)>
+<!ATTLIST layer title CDATA #REQUIRED>
+<!ATTLIST layer shapestore IDREF #REQUIRED>
+<!ATTLIST layer visible (true|false) "true">
+<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ATTLIST layer fill CDATA "None">
+<!ATTLIST layer stroke CDATA "#000000">
+<!ATTLIST layer stroke_width CDATA "1">
+
+
+<!-- a rasterlayer represents an image that has some geographic data
+ associated with it. The filename points to the image used.
+-->
+<!ELEMENT rasterlayer (projection?, classification?)>
+<!ATTLIST rasterlayer
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ visible (true|false) "true">
+
+
+<!-- Classification data -->
+<!ELEMENT classification (clnull?, clpoint*, clrange*, clcont*)>
+<!ATTLIST classification field CDATA #REQUIRED>
+<!ATTLIST classification field_type CDATA #REQUIRED>
+
+<!ELEMENT clnull (cldata*)>
+<!ELEMENT clpoint (cldata*)>
+<!ELEMENT clrange (cldata*)>
+<!ELEMENT clcont (cldata*)>
+
+<!ATTLIST clnull label CDATA #IMPLIED>
+
+<!ATTLIST clpoint value CDATA #REQUIRED>
+<!ATTLIST clpoint label CDATA #IMPLIED>
+
+<!ATTLIST clrange min CDATA #IMPLIED>
+<!ATTLIST clrange max CDATA #IMPLIED>
+<!ATTLIST clrange range CDATA #IMPLIED>
+<!ATTLIST clrange label CDATA #IMPLIED>
+
+<!ATTLIST clcont rmin CDATA #REQUIRED>
+<!ATTLIST clcont rmax CDATA #REQUIRED>
+<!ATTLIST clcont dmin CDATA #REQUIRED>
+<!ATTLIST clcont dmax CDATA #REQUIRED>
+
+<!-- Visual appearance of the classification
+
+ the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ELEMENT cldata EMPTY>
+<!ATTLIST cldata
+ stroke CDATA #IMPLIED
+ stroke_width CDATA #IMPLIED
+ fill CDATA #IMPLIED
+>
+
+
+<!-- a projection has a number of parameters
+-->
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA "" >
+
+<!-- just a simple parameter consisting of a value
+-->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
+
+
+<!-- The label layer contains text labels -->
+<!ELEMENT labellayer (label*) >
+
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ text CDATA #REQUIRED
+ halign (left|center|right) #REQUIRED
+ valign (top|center|bottom) #REQUIRED>
Added: packages/thuban/branches/upstream/current/Resources/XML/thuban-1.0.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/thuban-1.0.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/thuban-1.0.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- thuban-1.0.dtd
+
+ Copyright (C) 2001, 2003 by Intevation GmbH
+ Authors:
+ Jan-Oliver Wagner <jan at intevation.de>
+ Bernhard Herzog <bh at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+
+ $Revision: 1841 $
+ $Source$
+ $Id: thuban-1.0.dtd 1841 2003-10-21 10:49:03Z bh $
+-->
+
+<!-- a session contains zero or more database connections zero or more
+ datasources and and zero or more maps
+
+At some point, the namespace attribute will likely be used by Thuban to
+identify the version of the file format.
+-->
+
+<!ENTITY % shapesources "fileshapesource | derivedshapesource | dbshapesource">
+<!ENTITY % tables "filetable | jointable">
+<!ELEMENT session ((dbconnection | %shapesources; | %tables; )*, map*)>
+<!ATTLIST session
+ title CDATA #REQUIRED
+ xmlns CDATA #IMPLIED
+>
+
+
+<!--
+ A db connection represents the connection to a database.
+
+ Currently only connections to postgis databases are supported and
+ thus The dbtype attribute must be "postgis".
+-->
+
+<!ELEMENT dbconnection EMPTY>
+<!ATTLIST dbconnection
+ id ID #REQUIRED
+ dbtype CDATA #REQUIRED
+ dbname CDATA #REQUIRED
+ host CDATA ""
+ port CDATA ""
+ user CDATA ""
+>
+
+
+<!-- A dbshapesource represents a table with geometry data in a database
+
+ The dbconn attribute must be the id of a dbconnection element
+ occurring earlier in the document.
+-->
+
+<!ELEMENT dbshapesource EMPTY>
+<!ATTLIST dbshapesource
+ id ID #REQUIRED
+ dbconn IDREF #REQUIRED
+ tablename CDATA #REQUIRED
+>
+
+<!--
+ A fileshapesource is a source of shapes and perhaps attribute data
+ read from a file. The filetype attribute must be one of the
+ supported file types. Currently only "shapefile" is supported.
+ -->
+
+<!ELEMENT fileshapesource EMPTY>
+<!ATTLIST fileshapesource
+ id ID #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED
+>
+
+<!--
+ A derivedshapesource is a source of shapes and attribute data
+ derived from another shapesource for the shapes and a table for the
+ attribute data.
+ -->
+
+<!ELEMENT derivedshapesource EMPTY>
+<!ATTLIST derivedshapesource
+ id ID #REQUIRED
+ shapesource IDREF #REQUIRED
+ table IDREF #REQUIRED
+>
+
+
+<!-- a filetable points to the actual file that
+ contains the tabular data.
+
+ The filetype Attribute may be onve of "DBF" or "CSV"
+-->
+<!ELEMENT filetable EMPTY>
+<!ATTLIST filetable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED>
+
+<!--
+ A jointable is a table with the result of something equivalent to
+ this SQL Statement:
+
+ SELECT * FROM left JOIN right WHERE left.leftcolumn = right.rightcolumn;
+
+ The attributes left and right must be the ids of two tables defined
+ previously in the XML-Document file. leftcolumn and rightcolumn are
+ the column names to join on.
+
+ The jointype attribute should be either "INNER" or "LEFT OUTER".
+-->
+<!ELEMENT jointable EMPTY>
+<!ATTLIST jointable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ left IDREF #REQUIRED
+ leftcolumn CDATA #REQUIRED
+ right IDREF #REQUIRED
+ rightcolumn CDATA #REQUIRED
+ jointype CDATA #REQUIRED
+>
+
+<!-- A Map
+
+ A map consists of a number of layers
+ the projection refers to the projection
+ used to display the map. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed.
+-->
+<!ELEMENT map (projection?, (layer | rasterlayer)*, labellayer?)>
+<!ATTLIST map title CDATA #REQUIRED>
+
+<!-- a layer represents a set of geographic objects.
+ pointers to the actual data are stored.
+ The shapestore attributes contains the id of the data store
+ shown in the layer.
+ the projection refers to the projection
+ in which the data are stored. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed. Visibility is assumed true
+ unless otherwise specified.
+-->
+<!ELEMENT layer (projection?, classification?)>
+<!ATTLIST layer title CDATA #REQUIRED>
+<!ATTLIST layer shapestore IDREF #REQUIRED>
+<!ATTLIST layer visible (true|false) "true">
+<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ATTLIST layer fill CDATA "None">
+<!ATTLIST layer stroke CDATA "#000000">
+<!ATTLIST layer stroke_width CDATA "1">
+
+
+<!-- a rasterlayer represents an image that has some geographic data
+ associated with it. The filename points to the image used.
+-->
+<!ELEMENT rasterlayer (projection?, classification?)>
+<!ATTLIST rasterlayer
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ visible (true|false) "true">
+
+
+<!-- Classification data -->
+<!ELEMENT classification (clnull?, clpoint*, clrange*, clcont*)>
+<!ATTLIST classification field CDATA #REQUIRED>
+<!ATTLIST classification field_type CDATA #REQUIRED>
+
+<!ELEMENT clnull (cldata*)>
+<!ELEMENT clpoint (cldata*)>
+<!ELEMENT clrange (cldata*)>
+<!ELEMENT clcont (cldata*)>
+
+<!ATTLIST clnull label CDATA #IMPLIED>
+
+<!ATTLIST clpoint value CDATA #REQUIRED>
+<!ATTLIST clpoint label CDATA #IMPLIED>
+
+<!ATTLIST clrange min CDATA #IMPLIED>
+<!ATTLIST clrange max CDATA #IMPLIED>
+<!ATTLIST clrange range CDATA #IMPLIED>
+<!ATTLIST clrange label CDATA #IMPLIED>
+
+<!ATTLIST clcont rmin CDATA #REQUIRED>
+<!ATTLIST clcont rmax CDATA #REQUIRED>
+<!ATTLIST clcont dmin CDATA #REQUIRED>
+<!ATTLIST clcont dmax CDATA #REQUIRED>
+
+<!-- Visual appearance of the classification
+
+ the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ELEMENT cldata EMPTY>
+<!ATTLIST cldata
+ stroke CDATA #IMPLIED
+ stroke_width CDATA #IMPLIED
+ fill CDATA #IMPLIED
+>
+
+
+<!-- a projection has a number of parameters
+-->
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA ""
+ epsg CDATA #IMPLIED >
+
+<!-- just a simple parameter consisting of a value
+-->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
+
+
+<!-- The label layer contains text labels -->
+<!ELEMENT labellayer (label*) >
+
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ text CDATA #REQUIRED
+ halign (left|center|right) #REQUIRED
+ valign (top|center|bottom) #REQUIRED>
Added: packages/thuban/branches/upstream/current/Resources/XML/thuban-1.1.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/thuban-1.1.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/thuban-1.1.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- thuban-1.1.dtd
+
+ Copyright (C) 2001, 2003, 2004, 2005 by Intevation GmbH
+ Authors:
+ Jan-Oliver Wagner <jan at intevation.de>
+ Bernhard Herzog <bh at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+
+ $Revision: 2688 $
+ $Source$
+ $Id: thuban-1.1.dtd 2688 2006-06-30 12:27:20Z frank $
+-->
+
+<!-- a session contains zero or more database connections zero or more
+ datasources and and zero or more maps
+
+At some point, the namespace attribute will likely be used by Thuban to
+identify the version of the file format.
+-->
+
+<!ENTITY % shapesources "fileshapesource | derivedshapesource | dbshapesource">
+<!ENTITY % tables "filetable | jointable">
+<!ELEMENT session ((dbconnection | %shapesources; | %tables; )*, map*)>
+<!ATTLIST session
+ title CDATA #REQUIRED
+ xmlns CDATA #IMPLIED
+>
+
+
+<!--
+ A db connection represents the connection to a database.
+
+ Currently only connections to postgis databases are supported and
+ thus The dbtype attribute must be "postgis".
+-->
+
+<!ELEMENT dbconnection EMPTY>
+<!ATTLIST dbconnection
+ id ID #REQUIRED
+ dbtype CDATA #REQUIRED
+ dbname CDATA #REQUIRED
+ host CDATA ""
+ port CDATA ""
+ user CDATA ""
+>
+
+
+<!-- A dbshapesource represents a table with geometry data in a database
+
+ The dbconn attribute must be the id of a dbconnection element
+ occurring earlier in the document.
+-->
+
+<!ELEMENT dbshapesource EMPTY>
+<!ATTLIST dbshapesource
+ id ID #REQUIRED
+ dbconn IDREF #REQUIRED
+ tablename CDATA #REQUIRED
+ id_column CDATA #REQUIRED
+ geometry_column CDATA #REQUIRED
+>
+
+<!--
+ A fileshapesource is a source of shapes and perhaps attribute data
+ read from a file. The filetype attribute must be one of the
+ supported file types. Currently only "shapefile" is supported.
+ -->
+
+<!ELEMENT fileshapesource EMPTY>
+<!ATTLIST fileshapesource
+ id ID #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED
+>
+
+<!--
+ A derivedshapesource is a source of shapes and attribute data
+ derived from another shapesource for the shapes and a table for the
+ attribute data.
+ -->
+
+<!ELEMENT derivedshapesource EMPTY>
+<!ATTLIST derivedshapesource
+ id ID #REQUIRED
+ shapesource IDREF #REQUIRED
+ table IDREF #REQUIRED
+>
+
+
+<!-- a filetable points to the actual file that
+ contains the tabular data.
+
+ The filetype Attribute may be onve of "DBF" or "CSV"
+-->
+<!ELEMENT filetable EMPTY>
+<!ATTLIST filetable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ filetype CDATA #REQUIRED>
+
+<!--
+ A jointable is a table with the result of something equivalent to
+ this SQL Statement:
+
+ SELECT * FROM left JOIN right WHERE left.leftcolumn = right.rightcolumn;
+
+ The attributes left and right must be the ids of two tables defined
+ previously in the XML-Document file. leftcolumn and rightcolumn are
+ the column names to join on.
+
+ The jointype attribute should be either "INNER" or "LEFT OUTER".
+-->
+<!ELEMENT jointable EMPTY>
+<!ATTLIST jointable
+ id ID #REQUIRED
+ title CDATA #REQUIRED
+ left IDREF #REQUIRED
+ leftcolumn CDATA #REQUIRED
+ right IDREF #REQUIRED
+ rightcolumn CDATA #REQUIRED
+ jointype CDATA #REQUIRED
+>
+
+<!-- A Map
+
+ A map consists of a number of layers
+ the projection refers to the projection
+ used to display the map. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed.
+-->
+<!ELEMENT map (projection?, (layer | rasterlayer)*, labellayer?)>
+<!ATTLIST map title CDATA #REQUIRED>
+
+<!-- a layer represents a set of geographic objects.
+ pointers to the actual data are stored.
+ The shapestore attributes contains the id of the data store
+ shown in the layer.
+ the projection refers to the projection
+ in which the data are stored. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed. Visibility is assumed true
+ unless otherwise specified.
+-->
+<!ELEMENT layer (projection?, classification?)>
+<!ATTLIST layer title CDATA #REQUIRED>
+<!ATTLIST layer shapestore IDREF #REQUIRED>
+<!ATTLIST layer visible (true|false) "true">
+<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke, stroke_width and size may be omitted and default
+ to "None", "#000000", "1" and "5" respectively.
+ -->
+<!ATTLIST layer fill CDATA "None">
+<!ATTLIST layer stroke CDATA "#000000">
+<!ATTLIST layer stroke_width CDATA "1">
+<!ATTLIST layer size CDATA "5">
+
+
+<!-- a rasterlayer represents an image that has some geographic data
+ associated with it. The filename points to the image used.
+
+ The masktype should be one of "none", "bit" or "alpha".
+ The opacity is the opacity as a decimal floating point number in the
+ range 0.0 ... 1.0
+-->
+<!ELEMENT rasterlayer (projection?, classification?)>
+<!ATTLIST rasterlayer
+ title CDATA #REQUIRED
+ filename CDATA #REQUIRED
+ opacity CDATA #IMPLIED
+ masktype CDATA #IMPLIED
+ visible (true|false) "true">
+
+
+<!-- Classification data -->
+<!ELEMENT classification (clnull?, clpoint*, clrange*, clpattern*, clcont*)>
+<!ATTLIST classification field CDATA>
+<!ATTLIST classification field_type CDATA>
+
+<!ELEMENT clnull (cldata*)>
+<!ELEMENT clpoint (cldata*)>
+<!ELEMENT clrange (cldata*)>
+<!ELEMENT clpattern (cldata*)>
+<!ELEMENT clcont (cldata*)>
+
+<!ATTLIST clnull label CDATA #IMPLIED>
+
+<!ATTLIST clpoint value CDATA #REQUIRED>
+<!ATTLIST clpoint label CDATA #IMPLIED>
+
+<!ATTLIST clrange min CDATA #IMPLIED>
+<!ATTLIST clrange max CDATA #IMPLIED>
+<!ATTLIST clrange range CDATA #IMPLIED>
+<!ATTLIST clrange label CDATA #IMPLIED>
+
+<!ATTLIST clpattern pattern CDATA #REQUIRED>
+<!ATTLIST clpattern label CDATA #IMPLIED>
+
+<!ATTLIST clcont rmin CDATA #REQUIRED>
+<!ATTLIST clcont rmax CDATA #REQUIRED>
+<!ATTLIST clcont dmin CDATA #REQUIRED>
+<!ATTLIST clcont dmax CDATA #REQUIRED>
+
+<!-- Visual appearance of the classification
+
+ the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ TODO: Actually, 'size' is only sensible for points. But adding it to
+ clpoint would not be enough since the 'size' must also be available
+ for the clnull. And clnull again is applied for lines and polygons.
+ So, at some later point, maybe with introducing symbols, this
+ has to be improved.
+
+ All of fill, stroke, stroke_width and size may be omitted and default to
+ "None", "#000000", "1" and "5" respectively.
+ -->
+<!ELEMENT cldata EMPTY>
+<!ATTLIST cldata
+ stroke CDATA #IMPLIED
+ stroke_width CDATA #IMPLIED
+ fill CDATA #IMPLIED
+ size CDATA #IMPLIED
+>
+
+
+<!-- a projection has a number of parameters
+-->
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA ""
+ epsg CDATA #IMPLIED >
+
+<!-- just a simple parameter consisting of a value
+-->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
+
+
+<!-- The label layer contains text labels -->
+<!ELEMENT labellayer (label*) >
+
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ text CDATA #REQUIRED
+ halign (left|center|right) #REQUIRED
+ valign (top|center|bottom) #REQUIRED>
Added: packages/thuban/branches/upstream/current/Resources/XML/thuban.dtd
===================================================================
--- packages/thuban/branches/upstream/current/Resources/XML/thuban.dtd 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Resources/XML/thuban.dtd 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- thuban.dtd
+
+ Copyright (C) 2001, 2003 by Intevation GmbH
+ Authors:
+ Jan-Oliver Wagner <jan at intevation.de>
+
+ This program is free software under the GPL (>=v2)
+ Read the file COPYING coming with Thuban for details.
+
+ This DTD covers .thuban files for Thuban versions up to 0.2 and most
+ of the .thuban files generated by development/CVS versions of Thuban
+ between 0.2 and 0.8.
+ -->
+
+<!-- a session contains a number of maps and tables
+-->
+<!ELEMENT session (map*, table*)>
+<!ATTLIST session title CDATA #REQUIRED>
+
+<!-- a map consists of a number of layers
+ the projection refers to the projection
+ used for discplaing the map. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed.
+-->
+<!ELEMENT map (projection?, (layer | rasterlayer)*, labellayer?)>
+<!ATTLIST map title CDATA #REQUIRED>
+
+<!-- a layer represents a set of geographic objects.
+ pointers to the actual data are stored.
+ currently only a filename points to the data.
+ the projection refers to the projection
+ in which the data are stored. If the projection
+ is missing, geographic coordinates in decimal
+ degrees are assumed. Visibility is assumed true
+ unless otherwise specified.
+-->
+<!ELEMENT layer (projection?, classification?)>
+<!ATTLIST layer title CDATA #REQUIRED>
+<!ATTLIST layer filename CDATA #REQUIRED>
+<!ATTLIST layer visible (true|false) "true">
+
+<!-- the fill and stroke attributes can be either "None" or "#RRGGBB"
+ RGB hex values
+
+ All of fill, stroke and stroke_width may be omitted and default to
+ "None", "#000000" and "1" respectively.
+ -->
+<!ATTLIST layer fill CDATA "None">
+<!ATTLIST layer stroke CDATA "#000000">
+<!ATTLIST layer stroke_width CDATA "1">
+
+<!-- a rasterlayer represents an image that has some geographic data
+ associated with it. The filename points to the image used.
+-->
+<!ELEMENT rasterlayer (projection?, classification?)>
+<!ATTLIST rasterlayer title CDATA #REQUIRED>
+<!ATTLIST rasterlayer filename CDATA #REQUIRED>
+<!ATTLIST rasterlayer visible (true|false) "true">
+
+<!-- Classification data -->
+<!ELEMENT classification (clnull?, (clpoint | clrange | clcont)*)>
+<!ATTLIST classification field CDATA #REQUIRED>
+<!ATTLIST classification field_type CDATA #REQUIRED>
+
+<!ELEMENT clnull (cldata*)>
+<!ELEMENT clpoint (cldata*)>
+<!ELEMENT clrange (cldata*)>
+<!ELEMENT clcont (cldata*)>
+
+<!ATTLIST clnull label CDATA #IMPLIED>
+
+<!ATTLIST clpoint value CDATA #REQUIRED>
+<!ATTLIST clpoint label CDATA #IMPLIED>
+
+<!ATTLIST clrange min CDATA #IMPLIED>
+<!ATTLIST clrange max CDATA #IMPLIED>
+<!ATTLIST clrange range CDATA #IMPLIED>
+<!ATTLIST clrange label CDATA #IMPLIED>
+
+<!ATTLIST clcont rmin CDATA #REQUIRED>
+<!ATTLIST clcont rmax CDATA #REQUIRED>
+<!ATTLIST clcont dmin CDATA #REQUIRED>
+<!ATTLIST clcont dmax CDATA #REQUIRED>
+
+<!ELEMENT cldata EMPTY>
+<!ATTLIST cldata
+ stroke CDATA #IMPLIED
+ stroke_width CDATA #IMPLIED
+ fill CDATA #IMPLIED
+>
+
+<!-- a table points to the actual file that
+ contains the tabular data.
+-->
+<!ELEMENT table EMPTY>
+<!ATTLIST table title CDATA #REQUIRED>
+<!ATTLIST table filename CDATA #REQUIRED>
+
+<!-- a projection has a number of parameters
+-->
+<!ELEMENT projection (parameter*)>
+<!ATTLIST projection
+ name CDATA #IMPLIED >
+
+<!-- just a simple parameter consisting of a value
+-->
+<!ELEMENT parameter EMPTY>
+<!ATTLIST parameter value CDATA #REQUIRED>
+
+
+<!-- The label layer contains text labels -->
+<!ELEMENT labellayer (label*) >
+
+<!ELEMENT label EMPTY>
+<!ATTLIST label
+ x CDATA #REQUIRED
+ y CDATA #REQUIRED
+ text CDATA #REQUIRED
+ halign (left|center|right) #REQUIRED
+ valign (top|center|bottom) #REQUIRED>
Added: packages/thuban/branches/upstream/current/Thuban/Lib/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Lib/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Lib/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2001 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Thuban/Lib/classmapper.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Lib/classmapper.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Lib/classmapper.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,81 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+The provided class maintains a mapping between classes and objects.
+Instances of the class are used as keys, not classes, though.
+
+Usually layer classes and their instances are used in combination with
+layer property dialog classes in order to utilise the proper dialog
+for a given layer instance.
+
+"""
+
+__version__ = "$Revision: 2299 $"
+# $Source$
+# $Id: classmapper.py 2299 2004-07-26 16:08:07Z joey $
+
+
+class ClassMapper:
+ """
+ Thuban class to implement a mapping of classes and objects,
+ usually also classes.
+ """
+
+ mapping = None
+
+
+ def __init__(self):
+ """
+ Initialises a mapping.
+ """
+
+ self.mapping = []
+
+
+ def add(self, key_class, obj):
+ """
+ Register an object with a class.
+
+ This method adds the provided pair (key_class,obj) to the
+ internal list. Subsequently instances of key_class are used
+ to retrieved the stored object.
+ """
+
+ self.mapping.append((key_class, obj))
+
+
+ def get(self, instance):
+ """
+ Retrieve a stored object corresponding to the provided class
+ instance.
+ """
+
+ for key_class, obj in self.mapping:
+ if isinstance(instance, key_class):
+ return obj
+ return None
+
+
+ def has(self, instance):
+ """
+ Determine if the ClassMapper contains an object corresponding
+ to the provided instance
+ """
+
+ return self.get(instance) is not None
Added: packages/thuban/branches/upstream/current/Thuban/Lib/connector.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Lib/connector.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Lib/connector.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,181 @@
+# This module was copied almost verbatim from Sketch. The only change is
+# the base class of ConnectorError which was a Sketch specific exception
+# class.
+
+# Sketch - A Python-based interactive drawing program
+# Copyright (C) 1997, 1998, 2000, 2001, 2003 by Bernhard Herzog
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+__version__ = "$Revision: 1952 $"
+
+#
+# The Connector
+#
+
+import sys
+from types import MethodType
+
+from Thuban import _
+
+class ConnectorError(Exception):
+ pass
+
+class Connector:
+
+ def __init__(self):
+ self.connections = {}
+
+ def Connect(self, object, channel, function, args):
+ idx = id(object)
+ if self.connections.has_key(idx):
+ channels = self.connections[idx]
+ else:
+ channels = self.connections[idx] = {}
+
+ if channels.has_key(channel):
+ receivers = channels[channel]
+ else:
+ receivers = channels[channel] = []
+
+ info = (function, args)
+ try:
+ receivers.remove(info)
+ except ValueError:
+ pass
+ receivers.append(info)
+
+ def Disconnect(self, object, channel, function, args):
+ try:
+ receivers = self.connections[id(object)][channel]
+ except KeyError:
+ raise ConnectorError, \
+ _('no receivers for channel %s of %s') % (channel, object)
+ try:
+ receivers.remove((function, args))
+ except ValueError:
+ raise ConnectorError,\
+ _('receiver %s%s is not connected to channel %s of %s') \
+ % (function, args, channel, object)
+
+ if not receivers:
+ # the list of receivers is empty now, remove the channel
+ channels = self.connections[id(object)]
+ del channels[channel]
+ if not channels:
+ # the object has no more channels
+ del self.connections[id(object)]
+
+ def Issue(self, object, channel, *args):
+ #print object, channel, args
+ try:
+ receivers = self.connections[id(object)][channel]
+ except KeyError:
+ return
+ # Iterate over a copy of receivers because the receivers might
+ # unsubscribe themselves when receiving a message and Disconnect
+ # would modify receivers in place while we're iterating over it.
+ for func, fargs in receivers[:]:
+ try:
+ apply(func, args + fargs)
+ except:
+ sys.stderr.write(_("Warning: %s.%s: %s%s\n")
+ % (object, channel, func, fargs))
+ import traceback
+ traceback.print_exc()
+
+ def RemovePublisher(self, object):
+ i = id(object)
+ if self.connections.has_key(i):
+ del self.connections[i]
+ # don't use try: del ... ; except KeyError here. That would create a
+ # new reference of object in a traceback object and this method should
+ # be callable from a __del__ method (at least for versions prior
+ # Python 1.5)
+
+ def HasSubscribers(self, object):
+ return self.connections.has_key(id(object))
+
+ def print_connections(self):
+ # for debugging
+ for id, channels in self.connections.items():
+ for name, subscribers in channels.items():
+ print hex(id), name
+ for func, args in subscribers:
+ if type(func) == MethodType:
+ print _('\tmethod %s of %s') % (func.im_func.func_name,
+ func.im_self)
+ else:
+ print '\t', func
+
+
+
+_the_connector = Connector()
+
+Connect = _the_connector.Connect
+Issue = _the_connector.Issue
+RemovePublisher = _the_connector.RemovePublisher
+Disconnect = _the_connector.Disconnect
+def Subscribe(channel, function, *args):
+ return Connect(None, channel, function, args)
+
+
+class Publisher:
+
+ # Flag indicating whether the publisher instance was destroyed.
+ _was_destroyed = False
+
+ def __del__(self):
+ # the new finalization code in 1.5.1 might bind RemovePublisher
+ # to None before all objects derived from Publisher are deleted...
+ if RemovePublisher is not None:
+ RemovePublisher(self)
+
+ def Subscribe(self, channel, func, *args):
+ Connect(self, channel, func, args)
+
+ def Unsubscribe(self, channel, func, *args):
+ """Unsubscribe from the channel.
+
+ If the publisher's Destroy method has been called already, do
+ nothing, because the subscriptions will already have been
+ removed in Destroy and trying to disconnect it here will lead to
+ exceptions.
+ """
+ if not self._was_destroyed:
+ Disconnect(self, channel, func, args)
+
+ def issue(self, channel, *args):
+ apply(Issue, (self, channel,) + args)
+
+ def Destroy(self):
+ """Remove all subscriptions of messages sent by self."""
+ RemovePublisher(self)
+ self._was_destroyed = True
+
+
+class Conduit(Publisher):
+
+ def _do_forward(self, *args, **kw):
+ self.issue(args[-1], *args[:-1], **kw)
+
+ def subscribe_forwarding(self, channel, obj):
+ if obj is not None:
+ obj.Subscribe(channel, self._do_forward, channel)
+
+ def unsubscribe_forwarding(self, channel, obj):
+ if obj is not None:
+ obj.Unsubscribe(channel, self._do_forward, channel)
+
Added: packages/thuban/branches/upstream/current/Thuban/Lib/fileutil.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Lib/fileutil.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Lib/fileutil.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,222 @@
+# Copyright (c) 2001, 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Functions to deal with filenames
+"""
+
+__version__ = "$Revision: 1885 $"
+
+import os
+import os.path
+from tempfile import mktemp
+
+from string import join
+
+from Thuban import _
+
+def relative_filename_common(dir, absname, sep):
+ """Return a filename relative to dir for the absolute file name absname.
+ This is part the posix and nt versions have in common. Both dir and
+ absname are assumed to be normalized (as done with os.normpath)
+ absolute filenames without drive letters. sep is the platform
+ specific directory separator.
+ """
+
+ # split the filenames into their components. remove the first item
+ # since it will be always empty because both names are absolute.
+ dir_parts = dir.split(sep)[1:]
+ absname_parts = absname.split(sep)[1:]
+
+ # count the number of common parts at the start of dir_parts and
+ # absname_parts
+ max_common = min(len(dir_parts), len(absname_parts))
+ common = 0
+ while common < max_common and dir_parts[common] == absname_parts[common]:
+ common = common + 1
+
+ # If the common part is the root directory, return absname
+ if common == 0:
+ return absname
+
+ # for each directory under the common part prepend a '..'.
+ rel_parts = (len(dir_parts) - common) * ['..'] + absname_parts[common:]
+ return join(rel_parts, sep)
+
+
+def relative_filename_posix(dir, absname):
+ """Return a filename relative to dir for the absolute file name absname.
+
+ If absname is already a relative filename, return it unchanged. If
+ the common directory of dir and absname is /, return absname
+ unchanged. If dir is not an absolute name, raise TypeError.
+
+ This is the posix specific version of relative_filename.
+
+ Example:
+ >>> from fileutil import relative_filename_posix
+ >>> relative_filename_posix("/usr/local/lib/", "/usr/local/lib/python")
+ 'python'
+ >>> relative_filename_posix("/usr/local/lib/", "/usr/local/bin/python")
+ '../bin/python'
+ >>> relative_filename_posix("/usr/local/lib/", "/usr/bin/python")
+ '../../bin/python'
+ >>> relative_filename_posix("/usr/local/lib/", "/var/spool/mail")
+ '/var/spool/mail'
+ >>> relative_filename_posix("/home/", "xyzzy")
+ 'xyzzy'
+ >>> relative_filename_posix("home/", "/xyzzy")
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ File "fileutil.py", line 42, in relative_filename_posix
+ raise TypeError("first argument must be an absolute filename")
+ TypeError: first argument must be an absolute filename
+ """
+ # for posix, the common part does exactly what we need, except for
+ # the special cases and input checking. Import posixpath explicitly
+ # for that to faciliate testing
+ import posixpath
+ if not posixpath.isabs(absname):
+ return absname
+
+ if not posixpath.isabs(dir):
+ raise TypeError(_("first argument must be an absolute filename"))
+
+ dir = posixpath.normpath(dir)
+ absname = posixpath.normpath(absname)
+
+ return relative_filename_common(dir, absname, "/")
+
+def relative_filename_nt(dir, absname):
+ r"""Return a filename relative to dir for the absolute file name absname.
+
+ If absname is already a relative filename or if dir and absname are
+ on different drives, return absname. If the common directory of dir
+ and absname is the drive's root directory, return absname. If dir is
+ not an absolute name or either name doesn't have a drive letter,
+ raise TypeError.
+
+ This is the nt specific version of relative_filename.
+
+ Example:
+ >>> from fileutil import relative_filename_nt
+ >>> relative_filename_nt(r"C:\Programme\Python", r"C:\Programme\Thuban")
+ '..\\Thuban'
+ >>> relative_filename_nt(r"C:\Programme\Python", r"D:\Programme\Thuban")
+ 'D:\\Programme\\Thuban'
+ >>> relative_filename_nt(r"C:\Programme\Python", r"C:Programme")
+ 'C:Programme'
+ >>> relative_filename_nt(r"C:Programme\Python", r"C:Programme")
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ File "fileutil.py", line 123, in relative_filename_nt
+ raise TypeError("first argument must be an absolute filename")
+ TypeError: first argument must be an absolute filename
+ >>> relative_filename_nt(r"\Programme\Python", r"\Programme")
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ File "fileutil.py", line 120, in relative_filename_nt
+ raise TypeError("Both parameters must have a drive letter")
+ TypeError: Both parameters must have a drive letter
+ """
+ # first check the parameters. Imort ntpath directly to facilitate
+ # testing on non-nt systems.
+ import ntpath
+
+ dir = ntpath.normpath(dir)
+ absname = ntpath.normpath(absname)
+
+ dir_drive, dir_rest = ntpath.splitdrive(dir)
+ absname_drive, absname_rest = ntpath.splitdrive(absname)
+ #print dir_drive, dir_rest
+ #print absname_drive, absname_rest
+ if not dir_drive or not absname_drive:
+ raise TypeError(_("Both parameters must have a drive letter"))
+
+ if not ntpath.isabs(dir_rest):
+ raise TypeError(_("first argument must be an absolute filename"))
+
+ # handle some special cases
+ if not ntpath.isabs(absname_rest):
+ return absname
+
+ if dir_drive != absname_drive:
+ return absname
+
+ # Now both dir_rest and absname_rest are absolute filenames without
+ # drive letter. We can now use the common part to determine the
+ # relative name
+ return relative_filename_common(dir_rest, absname_rest, "\\")
+
+def get_application_dir():
+ """Determine the path to the .thuban directory. Create the directory
+ if it doesn't exist.
+
+ Under posix systems use the os.expanduser() method.
+ Under Win32 try to read the "Explorer/Shell Folders/" value "AppData".
+ """
+
+ if os.name == 'posix':
+ dir = os.path.expanduser("~/.thuban")
+ if not os.path.isdir(dir):
+ os.mkdir(dir)
+ return dir
+ elif os.name == 'nt':
+ regkey = 1
+ try:
+ import _winreg as wreg
+ except ImportError:
+ regkey = 0
+
+ if regkey:
+ try:
+ key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\"\
+ "Explorer\\Shell Folders")
+ dir = wreg.QueryValueEx(key, "AppData")[0]
+ dir = os.path.join(dir, "thuban")
+ except:
+ regkey = 0
+
+ if not regkey:
+ # The fallback. This should result in something like the
+ # user directory ...
+ guess = os.path.dirname(
+ os.path.dirname(os.path.dirname(mktemp()))
+ )
+ dir = os.path.join(guess, "thuban")
+ if not os.path.isdir(dir):
+ os.mkdir(dir)
+
+ return dir
+
+ else:
+ raise RuntimeError(_("No implementation of get_application_dir"
+ " available for platform") + os.name)
+
+# bind the appropriate version of relative_filename for the platform
+# we're currently running on.
+if os.name == "posix":
+ relative_filename = relative_filename_posix
+elif os.name == "nt":
+ relative_filename = relative_filename_nt
+else:
+ raise RuntimeError(_("No implementation of relative_filename"
+ " available for platform") + os.name)
+
+__test__ = {"relative_filename_posix": relative_filename_posix,
+ "relative_filename_nt": relative_filename_nt}
+
+# if run as a script, run doctest
+def _test():
+ import doctest, fileutil
+ # Pass an isprivate function that always returns true so that only
+ # items in __test__ are tested
+ return doctest.testmod(fileutil, isprivate = lambda *args: 1)
+
+if __name__ == "__main__":
+ _test()
Added: packages/thuban/branches/upstream/current/Thuban/Lib/version.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Lib/version.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Lib/version.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,42 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Version number handling"""
+
+__version__ = "$Revision: 2011 $"
+# $Source$
+# $Id: version.py 2011 2003-12-03 09:46:27Z bh $
+
+
+import re
+
+rx_version = re.compile("[0-9]+(\\.[0-9]+)*")
+
+def make_tuple(s):
+ """Return a tuple version of the version number string s
+
+ The version string must start with a sequence of decimal integers
+ separated by dots. The return value is a tuple of up to three
+ integers, one for each number at the beginnin of the version string.
+
+ If the string does not start with a number return None
+
+ Examples:
+ >>> import version
+ >>> version.make_tuple('1.2')
+ (1, 2)
+ >>> version.make_tuple('2.4.0.7')
+ (2, 4, 0)
+ >>> version.make_tuple('1.2+cvs.20031111')
+ (1, 2)
+ >>> version.make_tuple('foo')
+ >>>
+ """
+ match = rx_version.match(s)
+ if match:
+ return tuple(map(int, match.group(0).split(".")[:3]))
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,6 @@
+# Copyright (c) 2001 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
Added: packages/thuban/branches/upstream/current/Thuban/Model/base.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/base.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/base.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,77 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Various base classes that did not fit elsewhere.
+"""
+
+__version__ = "$Revision: 2413 $"
+
+from Thuban.Lib.connector import Publisher
+
+from messages import TITLE_CHANGED, CHANGED
+
+class TitledObject:
+
+ """Mix-in class for objects that have titles"""
+
+ def __init__(self, title):
+ self.title = title
+
+ def Title(self):
+ return self.title
+
+ def SetTitle(self, title):
+ self.title = title
+
+ # FIXME: The TitledObject is almost always used in conjunction
+ # with Modifiable (the only exceptions currently are the
+ # tables). We should reall derive TitledObject from modifiable
+ # (would be good for the tables too) but that's taking things a
+ # bit far at the moment.
+ if hasattr(self, 'changed'):
+ self.changed(TITLE_CHANGED, self)
+
+class Modifiable(Publisher):
+
+ """Class for objects maintaining a modified flag."""
+
+ def __init__(self):
+ self.modified = 0
+
+ def WasModified(self):
+ """Return true if the layer was modified"""
+ return self.modified
+
+ def UnsetModified(self):
+ """Unset the modified flag.
+
+ If the modified flag is changed from set to unset by the call,
+ issue a CHANGED message.
+
+ The modified flag itself is part of the state of the object so
+ some other objects such as a field in the status bar indication
+ whether e.g. the session has changed might be interested in
+ being notified when this flag has changed.
+ """
+ was_modified = self.modified
+ self.modified = 0
+ if was_modified:
+ self.issue(CHANGED)
+
+ def changed(self, channel = None, *args):
+ """Set the modified flag and optionally issue a message
+
+ The message is issued on the channel given by channel with args
+ as the arguments. If channel is None issue no message.
+
+ Subclasses should call this method whenever anything has
+ changed.
+ """
+ self.modified = 1
+ if channel is not None:
+ self.issue(channel, *args)
Added: packages/thuban/branches/upstream/current/Thuban/Model/classgen.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/classgen.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/classgen.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,481 @@
+# -*- encoding: iso-8859-1 -*-
+#
+# Copyright (c) 2003-2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+# Bernhard Herzog <bh at intevation.de> (2003)
+# Thomas Köster <tkoester at intevation.de> (2003)
+# Jonathan Coles <jonathan at intevation.de> (2003)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Functions to generate Classifications
+"""
+
+__version__ = "$Revision: 2441 $"
+# $Source$
+# $Id: classgen.py 2441 2004-12-09 10:50:34Z joey $
+
+import operator
+
+from color import Color, Transparent
+from range import Range
+from classification import Classification, ClassGroupSingleton, \
+ ClassGroupRange, ClassGroupProperties
+
+def generate_singletons(_list, ramp):
+ """Generate a new classification consisting solely of singletons.
+
+ The resulting classification will consist of one group for each
+ item in _list whose properties ramp between 'prop1' and 'prop2'.
+
+ _list -- a list of values for each singleton
+
+ ramp -- an object which implements the CustomRamp interface
+ """
+
+ clazz = Classification()
+
+ i = 0
+ maxValue = float(len(_list) - 1)
+ if maxValue < 1: maxValue = 1
+
+ for value in _list:
+ prop = ramp.GetProperties(i / maxValue)
+ clazz.AppendGroup(ClassGroupSingleton(value, prop))
+ i += 1
+
+ return clazz
+
+def generate_uniform_distribution(min, max, numGroups, ramp, intStep = False):
+ """Generate a classification with numGroups range groups
+ each with the same interval.
+
+ intStep -- force the calculated stepping to an integer.
+ Useful if the values are integers but the
+ number of groups specified doesn't evenly
+ divide (max - min).
+ """
+
+ clazz = Classification()
+
+ cur_min = min
+
+ end = "["
+ maxValue = float(numGroups - 1)
+ if maxValue < 1: maxValue = 1
+
+ for i in range(1, numGroups + 1):
+
+ prop = ramp.GetProperties(float(i-1) / maxValue)
+
+ if intStep:
+ cur_max = min + int(round((i * (max - min + 1)) / float(numGroups)))
+ else:
+ cur_max = min + (i * (max - min)) / float(numGroups)
+
+ if i == numGroups:
+ cur_max = max
+ end = "]"
+
+ if cur_min == cur_max:
+ _range = Range(("[", cur_min, cur_max, "]"))
+ else:
+ _range = Range(("[", cur_min, cur_max, end))
+
+ clazz.AppendGroup(ClassGroupRange(_range, prop))
+
+ cur_min = cur_max
+
+ return clazz
+
+def generate_quantiles(_list, percents, ramp, _range):
+ """Generates a Classification which has groups of ranges that
+ represent quantiles of _list at the percentages given in percents.
+ Only the values that fall within _range are considered.
+
+ Returns a tuple (adjusted, Classification) where adjusted is
+ True if the Classification does not exactly represent the given
+ range, or if the Classification is empty.
+
+ _list -- a sort list of values
+
+ percents -- a sorted list of floats in the range 0.0-1.0 which
+ represent the upper bound of each quantile. the
+ union of all percentiles should be the entire
+ range from 0.0-1.0
+
+ ramp -- an object which implements the CustomRamp interface
+
+ _range -- a Range object
+
+ Raises a Value Error if 'percents' has fewer than two items, or
+ does not cover the entire range.
+ """
+
+ clazz = Classification()
+ quantiles = calculate_quantiles(_list, percents, _range)
+ adjusted = True
+
+ if quantiles is not None:
+
+ numGroups = len(quantiles[3])
+
+ if numGroups != 0:
+
+ adjusted = quantiles[0]
+
+ start, min, endMax, right = _range.GetRange()
+
+ oldp = 0
+ i = 1
+ end = "]"
+
+ maxValue = float(numGroups - 1)
+ if maxValue < 1: maxValue = 1
+ for (q, p) in quantiles[3]:
+
+ prop = ramp.GetProperties(float(i-1) / maxValue)
+
+ if i == numGroups:
+ max = endMax
+ end = right
+ else:
+ max = _list[q]
+
+ group = ClassGroupRange(Range((start, min, max, end)), prop)
+
+ group.SetLabel("%s%% - %s%%" % (round(oldp*100, 2),
+ round(p*100, 2)))
+ oldp = p
+ start = "]"
+ min = max
+ clazz.AppendGroup(group)
+ i += 1
+
+ return (adjusted, clazz)
+
+
+def calculate_quantiles(_list, percents, _range):
+ """Calculate quantiles for the given _list of percents from the
+ sorted list of values that are in range.
+
+ This may not actually generate len(percents) quantiles if
+ many of the values that fall on quantile borders are the same.
+
+ Returns a tuple of the form:
+ (adjusted, minIndex, maxIndex, [quantile_list])
+
+ where adjusted is True if the the quantile percentages differ from
+ those supplied, minIndex is the index into _list where the
+ minimum value used is located, maxIndex is the index into _list
+ where the maximum value used is located, and quantile_list is a
+ list of tuples of the form: (list_index, quantile_percentage)
+
+ Returns None, if no quantiles could be generated based on the
+ given range or input list.
+
+ _list -- a sort list of values
+
+ percents -- a sorted list of floats in the range 0.0-1.0 which
+ represent the upper bound of each quantile. the
+ union of all percentiles should be the entire
+ range from 0.0-1.0
+
+ _range -- a Range object
+
+ Raises a Value Error if 'percents' has fewer than two items, or
+ does not cover the entire range.
+ """
+
+ quantiles = []
+ adjusted = False
+
+ if len(percents) <= 1:
+ raise ValueError("percents parameter must have more than one item")
+
+ if percents[-1] != 1.0:
+ raise ValueError("percents does not cover the entire range")
+
+ #
+ # find what part of the _list range covers
+ #
+ minIndex = -1
+ maxIndex = -2
+ for i in xrange(0, len(_list), 1):
+ if operator.contains(_range, _list[i]):
+ minIndex = i
+ break
+
+ for i in xrange(len(_list)-1, -1, -1):
+ if operator.contains(_range, _list[i]):
+ maxIndex = i
+ break
+
+ numValues = maxIndex - minIndex + 1
+
+ if numValues > 0:
+
+ #
+ # build a list of unique indices into list of where each
+ # quantile *should* be. set adjusted if the resulting
+ # indices are different
+ #
+ quantiles = {}
+ for p in percents:
+ index = min(minIndex + int(p*numValues)-1, maxIndex)
+
+ adjusted = adjusted \
+ or quantiles.has_key(index) \
+ or ((index - minIndex + 1) / float(numValues)) != p
+
+ quantiles[index] = 0
+
+ quantiles = quantiles.keys()
+ quantiles.sort()
+
+ #
+ # the current quantile index must be strictly greater than
+ # the lowerBound
+ #
+ lowerBound = minIndex - 1
+
+ for qindex in xrange(len(quantiles)):
+ if lowerBound >= maxIndex:
+ # discard higher quantiles
+ quantiles = quantiles[:qindex]
+ break
+
+ # lowerBound + 1 is always a valid index
+
+ #
+ # bump up the current quantile index to be a usable index
+ # if it currently falls below the lowerBound
+ #
+ if quantiles[qindex] <= lowerBound:
+ quantiles[qindex] = lowerBound + 1
+
+ listIndex = quantiles[qindex]
+ value = _list[listIndex]
+
+ #
+ # look for similar values around the quantile index
+ #
+ lindex = listIndex - 1
+ while lindex > lowerBound and value == _list[lindex]:
+ lindex -= 1
+ lcount = (listIndex - 1) - lindex
+
+ rindex = listIndex + 1
+ while rindex < maxIndex + 1 and value == _list[rindex]:
+ rindex += 1
+ rcount = (listIndex + 1) - rindex
+
+ #
+ # adjust the current quantile index based on how many
+ # numbers in the _list are the same as the current value
+ #
+ newIndex = listIndex
+ if lcount == rcount:
+ if lcount != 0:
+ #
+ # there are an equal number of numbers to the left
+ # and right, try going to the left first unless
+ # doing so creates an empty quantile.
+ #
+ if lindex != lowerBound:
+ newIndex = lindex
+ else:
+ newIndex = rindex - 1
+
+ elif lcount < rcount:
+ # there are fewer items to the left, so
+ # try going to the left first unless
+ # doing so creates an empty quantile.
+ if lindex != lowerBound:
+ newIndex = lindex
+ else:
+ newIndex = rindex - 1
+
+ elif rcount < lcount:
+ # there are fewer items to the right, so go to the right
+ newIndex = rindex - 1
+
+ adjusted = adjusted or newIndex != listIndex
+
+ quantiles[qindex] = newIndex
+ lowerBound = quantiles[qindex]
+
+ if len(quantiles) == 0:
+ return None
+ else:
+ return (adjusted, minIndex, maxIndex,
+ [(q, (q - minIndex+1) / float(numValues)) \
+ for q in quantiles])
+
+class CustomRamp:
+
+ def __init__(self, prop1, prop2):
+ """Create a ramp between prop1 and prop2."""
+ self.prop1 = prop1
+ self.prop2 = prop2
+
+ def GetRamp(self):
+ """Return this ramp."""
+ return self
+
+ def GetProperties(self, index):
+ """Return a ClassGroupProperties object whose properties
+ represent a point at 'index' between prop1 and prop2 in
+ the constructor.
+
+ index -- a value such that 0 <= index <= 1
+ """
+
+ if not (0 <= index <= 1):
+ raise ValueError(_("invalid index"))
+
+ newProps = ClassGroupProperties()
+
+ self.__SetProperty(self.prop1.GetLineColor(),
+ self.prop2.GetLineColor(),
+ index, newProps.SetLineColor)
+ self.__SetProperty(self.prop1.GetFill(), self.prop2.GetFill(),
+ index, newProps.SetFill)
+
+ w = (self.prop2.GetLineWidth() - self.prop1.GetLineWidth()) \
+ * index \
+ + self.prop1.GetLineWidth()
+ newProps.SetLineWidth(int(round(w)))
+
+ s = (self.prop2.GetSize() - self.prop1.GetSize()) \
+ * index \
+ + self.prop1.GetSize()
+ newProps.SetSize(int(round(s)))
+
+ return newProps
+
+ def __SetProperty(self, color1, color2, index, setf):
+ """Use setf to set the appropriate property for the point
+ index percent between color1 and color2. setf is a function
+ to call that accepts a Color object or Transparent.
+ """
+
+ if color1 is Transparent and color2 is Transparent:
+ setf(Transparent)
+ elif color1 is Transparent:
+ setf(Color(
+ color2.red * index,
+ color2.green * index,
+ color2.blue * index))
+ elif color2 is Transparent:
+ setf(Color(
+ color1.red * index,
+ color1.green * index,
+ color1.blue * index))
+ else:
+ setf(Color(
+ (color2.red - color1.red) * index + color1.red,
+ (color2.green - color1.green) * index + color1.green,
+ (color2.blue - color1.blue) * index + color1.blue))
+
+class MonochromaticRamp(CustomRamp):
+ """Helper class to make ramps between two colors."""
+
+ def __init__(self, start, end):
+ """Create a Monochromatic Ramp.
+
+ start -- starting Color
+
+ end -- ending Color
+ """
+ sp = ClassGroupProperties()
+ sp.SetLineColor(start)
+ sp.SetFill(start)
+
+ ep = ClassGroupProperties()
+ ep.SetLineColor(end)
+ ep.SetFill(end)
+
+ CustomRamp.__init__(self, sp, ep)
+
+grey_ramp = MonochromaticRamp(Color(1, 1, 1), Color(0, 0, 0))
+red_ramp = MonochromaticRamp(Color(1, 1, 1), Color(.8, 0, 0))
+green_ramp = MonochromaticRamp(Color(1, 1, 1), Color(0, .8, 0))
+blue_ramp = MonochromaticRamp(Color(1, 1, 1), Color(0, 0, .8))
+green_to_red_ramp = MonochromaticRamp(Color(0, .8, 0), Color(1, 0, 0))
+
+class HotToColdRamp:
+ """A ramp that generates properties with colors ranging from
+ 'hot' colors (e.g. red, orange) to 'cold' colors (e.g. green, blue)
+ """
+
+ def GetRamp(self):
+ """Return this ramp."""
+ return self
+
+ def GetProperties(self, index):
+ """Return a ClassGroupProperties object whose properties
+ represent a point at 'index' between "hot" and "cold".
+
+ index -- a value such that 0 <= index <= 1
+ """
+
+ clr = [1.0, 1.0, 1.0]
+
+ if index < .25:
+ clr[0] = 0
+ clr[1] = 4 * index
+ elif index < .5:
+ clr[0] = 0
+ clr[2] = 1 + 4 * (.25 - index)
+ elif index < .75:
+ clr[0] = 4 * (index - .5)
+ clr[2] = 0
+ else:
+ clr[1] = 1 + 4 * (.75 - index)
+ clr[2] = 0
+
+ prop = ClassGroupProperties()
+ prop.SetLineColor(Color(clr[0], clr[1], clr[2]))
+ prop.SetFill(Color(clr[0], clr[1], clr[2]))
+
+ return prop
+
+class FixedRamp:
+ """FixedRamp allows particular properties of a ramp to be
+ held constant over the ramp.
+ """
+
+ def __init__(self, ramp, fixes):
+ """
+ ramp -- a source ramp to get the default properties
+
+ fixes -- a tuple (lineColor, lineWidth, fillColor) such that
+ if any item is not None, the appropriate property will
+ be fixed to that item value.
+ """
+
+ self.fixes = fixes
+ self.ramp = ramp
+
+ def GetRamp(self):
+ """Return this ramp."""
+ return self
+
+ def GetProperties(self, index):
+ """Return a ClassGroupProperties object whose properties
+ represent a point at 'index' between the properties in
+ the ramp that initialized this FixedRamp.
+
+ index -- a value such that 0 <= index <= 1
+ """
+
+ props = self.ramp.GetProperties(index)
+ if self.fixes[0] is not None: props.SetLineColor(self.fixes[0])
+ if self.fixes[1] is not None: props.SetLineWidth(self.fixes[1])
+ if self.fixes[2] is not None: props.SetFill(self.fixes[2])
+
+ return props
Added: packages/thuban/branches/upstream/current/Thuban/Model/classification.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/classification.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/classification.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,856 @@
+# Copyright (c) 2001, 2003, 2005, 2006 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+# Jan-Oliver Wagner <jan at intevation.de> (2005)
+# Frank Koormann <frank at intevation.de> (2006)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2688 $"
+
+"""
+A Classification provides a mapping from an input value
+to data. This mapping can be specified in two ways.
+First, specific values can be associated with data.
+Second, ranges can be associated with data such that if
+an input value falls with a range that data is returned.
+If no mapping can be found then default data will
+be returned. Input values must be hashable objects
+
+See the description of FindGroup() for more information
+on the mapping algorithm.
+"""
+
+import copy, operator, types
+import re
+
+from Thuban import _
+
+from messages import \
+ LAYER_PROJECTION_CHANGED, \
+ LAYER_LEGEND_CHANGED, \
+ LAYER_VISIBILITY_CHANGED,\
+ CLASS_CHANGED
+
+from Thuban.Model.color import Color, Transparent, Black
+from Thuban.Model.range import Range
+
+import Thuban.Model.layer
+
+from Thuban.Lib.connector import Publisher
+
+class Classification(Publisher):
+ """Encapsulates the classification of layer.
+
+ The Classification divides some kind of data into Groups which
+ are associated with properties. Later the properties can be
+ retrieved by matching data values to the appropriate group.
+ """
+
+ def __init__(self):
+ """Initialize a classification."""
+
+ self.__groups = []
+
+ self.SetDefaultGroup(ClassGroupDefault())
+
+ def __iter__(self):
+ return ClassIterator(self.__groups)
+
+ def __deepcopy__(self, memo):
+ clazz = Classification()
+
+ clazz.__groups[0] = copy.deepcopy(self.__groups[0])
+
+ for i in range(1, len(self.__groups)):
+ clazz.__groups.append(copy.deepcopy(self.__groups[i]))
+
+ return clazz
+
+ def __SendNotification(self):
+ """Notify the layer that this class has changed."""
+ self.issue(CLASS_CHANGED)
+
+ def __getattr__(self, attr):
+ """Generate the compiled classification on demand"""
+ if attr == "_compiled_classification":
+ self._compile_classification()
+ return self._compiled_classification
+ raise AttributeError(attr)
+
+ def _compile_classification(self):
+ """Generate the compiled classification
+
+ The compiled classification is a more compact representation of
+ the classification groups that is also more efficient for
+ performing the classification.
+
+ The compiled classification is a list of tuples. The first
+ element of the tuple is a string which describes the rest of the
+ tuple. There are two kinds of tuples:
+
+ 'singletons'
+
+ The second element of the tuple is a dictionary which
+ combines several consecutive ClassGroupSingleton instances.
+ The dictionary maps the values of the singletons (as
+ returned by the GetValue() method) to the corresponding
+ group.
+
+ 'range'
+
+ The tuple describes a ClassGroupRange instance. The tuples
+ second element is a tuple fo the form (lfunc, min, max,
+ rfunc, group) where group is the original group object,
+ lfunc and rfuct are comparison functions and min and max are
+ lower and upper bounds of the range. Given a value and such
+ a tuple the group matches if and only if
+
+ lfunc(min, value) and rfunc(max, value)
+
+ is true.
+
+ 'pattern'
+
+ The tuple contains the compiled regular expression object and
+ the original group object.
+
+ The compiled classification is bound to
+ self._compile_classification.
+ """
+ compiled = []
+ for group in self.__groups[1:]:
+ if isinstance(group, ClassGroupSingleton):
+ if not compiled or compiled[-1][0] != "singletons":
+ compiled.append(("singletons", {}))
+ compiled[-1][1].setdefault(group.GetValue(), group)
+ elif isinstance(group, ClassGroupPattern):
+ pattern = re.compile(group.GetPattern())
+ compiled.append(("pattern", (pattern, group)))
+ elif isinstance(group, ClassGroupRange):
+ left, min, max, right = group.GetRangeTuple()
+ if left == "[":
+ lfunc = operator.le
+ elif left == "]":
+ lfunc = operator.lt
+ if right == "[":
+ rfunc = operator.gt
+ elif right == "]":
+ rfunc = operator.ge
+ compiled.append(("range", (lfunc, min, max, rfunc, group)))
+ else:
+ raise TypeError("Unknown group type %s", group)
+ self._compiled_classification = compiled
+
+ def _clear_compiled_classification(self):
+ """Reset the compiled classification.
+
+ If will be created on demand when self._compiled_classification
+ is accessed again.
+
+ Call this method whenever self.__groups is modified.
+ """
+ try:
+ del self._compiled_classification
+ except:
+ pass
+
+ #
+ # these SetDefault* methods are really only provided for
+ # some backward compatibility. they should be considered
+ # for removal once all the classification code is finished.
+ #
+
+ def SetDefaultFill(self, fill):
+ """Set the default fill color.
+
+ fill -- a Color object.
+ """
+ self.GetDefaultGroup().GetProperties().SetFill(fill)
+ self.__SendNotification()
+
+ def GetDefaultFill(self):
+ """Return the default fill color."""
+ return self.GetDefaultGroup().GetProperties().GetFill()
+
+ def SetDefaultLineColor(self, color):
+ """Set the default line color.
+
+ color -- a Color object.
+ """
+ self.GetDefaultGroup().GetProperties().SetLineColor(color)
+ self.__SendNotification()
+
+ def GetDefaultLineColor(self):
+ """Return the default line color."""
+ return self.GetDefaultGroup().GetProperties().GetLineColor()
+
+ def SetDefaultLineWidth(self, lineWidth):
+ """Set the default line width.
+
+ lineWidth -- an integer > 0.
+ """
+ assert isinstance(lineWidth, types.IntType)
+ self.GetDefaultGroup().GetProperties().SetLineWidth(lineWidth)
+ self.__SendNotification()
+
+ def GetDefaultLineWidth(self):
+ """Return the default line width."""
+ return self.GetDefaultGroup().GetProperties().GetLineWidth()
+
+
+ #
+ # The methods that manipulate self.__groups have to be kept in
+ # sync. We store the default group in index 0 to make it
+ # convienent to iterate over the classification's groups, but
+ # from the user's perspective the first (non-default) group is
+ # at index 0 and the DefaultGroup is a special entity.
+ #
+
+ def SetDefaultGroup(self, group):
+ """Set the group to be used when a value can't be classified.
+
+ group -- group that the value maps to.
+ """
+ assert isinstance(group, ClassGroupDefault)
+ if len(self.__groups) > 0:
+ self.__groups[0] = group
+ else:
+ self.__groups.append(group)
+ self.__SendNotification()
+
+ def GetDefaultGroup(self):
+ """Return the default group."""
+ return self.__groups[0]
+
+ def AppendGroup(self, item):
+ """Append a new ClassGroup item to the classification.
+
+ item -- this must be a valid ClassGroup object
+ """
+
+ self.InsertGroup(self.GetNumGroups(), item)
+
+ def InsertGroup(self, index, group):
+ assert isinstance(group, ClassGroup)
+ self.__groups.insert(index + 1, group)
+ self._clear_compiled_classification()
+ self.__SendNotification()
+
+ def RemoveGroup(self, index):
+ """Remove the classification group with the given index"""
+ self.__groups.pop(index + 1)
+ self._clear_compiled_classification()
+ self.__SendNotification()
+
+ def ReplaceGroup(self, index, group):
+ assert isinstance(group, ClassGroup)
+ self.__groups[index + 1] = group
+ self._clear_compiled_classification()
+ self.__SendNotification()
+
+ def GetGroup(self, index):
+ return self.__groups[index + 1]
+
+ def GetNumGroups(self):
+ """Return the number of non-default groups in the classification."""
+ return len(self.__groups) - 1
+
+ def FindGroup(self, value):
+ """Return the group that matches the value.
+
+ Groups are effectively checked in the order the were added to
+ the Classification.
+
+ value -- the value to classify. If there is no mapping or value
+ is None, return the default properties
+ """
+
+ if value is not None:
+ for typ, params in self._compiled_classification:
+ if typ == "singletons":
+ group = params.get(value)
+ if group is not None:
+ return group
+ elif typ == "range":
+ lfunc, min, max, rfunc, g = params
+ if lfunc(min, value) and rfunc(max, value):
+ return g
+ elif typ == "pattern":
+ # TODO: make pattern more robust. The following chrashes
+ # if accidently be applied on non-string columns.
+ # Usually the UI prevents this.
+ p, g = params
+ if p.match(value):
+ return g
+
+ return self.GetDefaultGroup()
+
+ def GetProperties(self, value):
+ """Return the properties associated with the given value.
+
+ Use this function rather than Classification.FindGroup().GetProperties()
+ since the returned group may be a ClassGroupMap which doesn't support
+ a call to GetProperties().
+ """
+
+ group = self.FindGroup(value)
+ if isinstance(group, ClassGroupMap):
+ return group.GetPropertiesFromValue(value)
+ else:
+ return group.GetProperties()
+
+ def TreeInfo(self):
+ items = []
+
+ def build_color_item(text, color):
+ if color is Transparent:
+ return ("%s: %s" % (text, _("None")), None)
+
+ return ("%s: (%.3f, %.3f, %.3f)" %
+ (text, color.red, color.green, color.blue),
+ color)
+
+ def build_item(group, string):
+ label = group.GetLabel()
+ if label == "":
+ label = string
+ else:
+ label += " (%s)" % string
+
+ props = group.GetProperties()
+ i = []
+ v = props.GetLineColor()
+ i.append(build_color_item(_("Line Color"), v))
+ v = props.GetLineWidth()
+ i.append(_("Line Width: %s") % v)
+
+ # Note: Size is owned by all properties, so
+ # a size will also appear where it does not
+ # make sense like for lines and polygons.
+ v = props.GetSize()
+ i.append(_("Size: %s") % v)
+
+ v = props.GetFill()
+ i.append(build_color_item(_("Fill"), v))
+ return (label, i)
+
+ for p in self:
+ items.append(build_item(p, p.GetDisplayText()))
+
+ return (_("Classification"), items)
+
+class ClassIterator:
+ """Allows the Groups in a Classifcation to be interated over.
+
+ The items are returned in the following order:
+ default data, singletons, ranges, maps
+ """
+
+ def __init__(self, data): #default, points, ranges, maps):
+ """Constructor.
+
+ default -- the default group
+
+ points -- a list of singleton groups
+
+ ranges -- a list of range groups
+
+ maps -- a list of map groups
+ """
+
+ self.data = data
+ self.data_index = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ """Return the next item."""
+
+ if self.data_index >= len(self.data):
+ raise StopIteration
+ else:
+ d = self.data[self.data_index]
+ self.data_index += 1
+ return d
+
+class ClassGroupProperties:
+ """Represents the properties of a single Classification Group.
+
+ These are used when rendering a layer."""
+
+ # TODO: Actually, size is only relevant for point objects.
+ # Eventually it should be spearated, e.g. when introducing symbols.
+
+ def __init__(self, props = None):
+ """Constructor.
+
+ props -- a ClassGroupProperties object. The class is copied if
+ prop is not None. Otherwise, a default set of properties
+ is created such that: line color = Black, line width = 1,
+ size = 5 and fill color = Transparent
+ """
+
+ if props is not None:
+ self.SetProperties(props)
+ else:
+ self.SetLineColor(Black)
+ self.SetLineWidth(1)
+ self.SetSize(5)
+ self.SetFill(Transparent)
+
+ def SetProperties(self, props):
+ """Set this class's properties to those in class props."""
+
+ assert isinstance(props, ClassGroupProperties)
+ self.SetLineColor(props.GetLineColor())
+ self.SetLineWidth(props.GetLineWidth())
+ self.SetSize(props.GetSize())
+ self.SetFill(props.GetFill())
+
+ def GetLineColor(self):
+ """Return the line color as a Color object."""
+ return self.__stroke
+
+ def SetLineColor(self, color):
+ """Set the line color.
+
+ color -- the color of the line. This must be a Color object.
+ """
+
+ self.__stroke = color
+
+ def GetLineWidth(self):
+ """Return the line width."""
+ return self.__strokeWidth
+
+ def SetLineWidth(self, lineWidth):
+ """Set the line width.
+
+ lineWidth -- the new line width. This must be > 0.
+ """
+ assert isinstance(lineWidth, types.IntType)
+ if (lineWidth < 1):
+ raise ValueError(_("lineWidth < 1"))
+
+ self.__strokeWidth = lineWidth
+
+ def GetSize(self):
+ """Return the size."""
+ return self.__size
+
+ def SetSize(self, size):
+ """Set the size.
+
+ size -- the new size. This must be > 0.
+ """
+ assert isinstance(size, types.IntType)
+ if (size < 1):
+ raise ValueError(_("size < 1"))
+
+ self.__size = size
+
+ def GetFill(self):
+ """Return the fill color as a Color object."""
+ return self.__fill
+
+ def SetFill(self, fill):
+ """Set the fill color.
+
+ fill -- the color of the fill. This must be a Color object.
+ """
+
+ self.__fill = fill
+
+ def __eq__(self, other):
+ """Return true if 'props' has the same attributes as this class"""
+
+ #
+ # using 'is' over '==' results in a huge performance gain
+ # in the renderer
+ #
+ return isinstance(other, ClassGroupProperties) \
+ and (self.__stroke is other.__stroke or \
+ self.__stroke == other.__stroke) \
+ and (self.__fill is other.__fill or \
+ self.__fill == other.__fill) \
+ and self.__strokeWidth == other.__strokeWidth\
+ and self.__size == other.__size
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __copy__(self):
+ return ClassGroupProperties(self)
+
+ def __deepcopy__(self):
+ return ClassGroupProperties(self)
+
+ def __repr__(self):
+ return repr((self.__stroke, self.__strokeWidth, self.__size,
+ self.__fill))
+
+class ClassGroup:
+ """A base class for all Groups within a Classification"""
+
+ def __init__(self, label = "", props = None, group = None):
+ """Constructor.
+
+ label -- A string representing the Group's label
+ """
+
+ if group is not None:
+ self.SetLabel(copy.copy(group.GetLabel()))
+ self.SetProperties(copy.copy(group.GetProperties()))
+ self.SetVisible(group.IsVisible())
+ else:
+ self.SetLabel(label)
+ self.SetProperties(props)
+ self.SetVisible(True)
+
+ def GetLabel(self):
+ """Return the Group's label."""
+ return self.label
+
+ def SetLabel(self, label):
+ """Set the Group's label.
+
+ label -- a string representing the Group's label. This must
+ not be None.
+ """
+ assert isinstance(label, types.StringTypes)
+ self.label = label
+
+ def GetDisplayText(self):
+ assert False, "GetDisplay must be overridden by subclass!"
+ return ""
+
+ def Matches(self, value):
+ """Determines if this Group is associated with the given value.
+
+ Returns False. This needs to be overridden by all subclasses.
+ """
+ assert False, "GetMatches must be overridden by subclass!"
+ return False
+
+ def GetProperties(self):
+ """Return the properties associated with the given value."""
+
+ return self.prop
+
+ def SetProperties(self, prop):
+ """Set the properties associated with this Group.
+
+ prop -- a ClassGroupProperties object. if prop is None,
+ a default set of properties is created.
+ """
+
+ if prop is None: prop = ClassGroupProperties()
+ assert isinstance(prop, ClassGroupProperties)
+ self.prop = prop
+
+ def IsVisible(self):
+ return self.visible
+
+ def SetVisible(self, visible):
+ self.visible = visible
+
+ def __eq__(self, other):
+ return isinstance(other, ClassGroup) \
+ and self.label == other.label \
+ and self.GetProperties() == other.GetProperties()
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __repr__(self):
+ return repr(self.label) + ", " + repr(self.GetProperties())
+
+class ClassGroupSingleton(ClassGroup):
+ """A Group that is associated with a single value."""
+
+ def __init__(self, value = 0, props = None, label = "", group = None):
+ """Constructor.
+
+ value -- the associated value.
+
+ prop -- a ClassGroupProperites object. If prop is None a default
+ set of properties is created.
+
+ label -- a label for this group.
+ """
+ ClassGroup.__init__(self, label, props, group)
+
+ self.SetValue(value)
+
+ def __copy__(self):
+ return ClassGroupSingleton(self.GetValue(),
+ self.GetProperties(),
+ self.GetLabel())
+
+ def __deepcopy__(self, memo):
+ return ClassGroupSingleton(self.GetValue(), group = self)
+
+ def GetValue(self):
+ """Return the associated value."""
+ return self.__value
+
+ def SetValue(self, value):
+ """Associate this Group with the given value."""
+ self.__value = value
+
+ def Matches(self, value):
+ """Determine if the given value matches the associated Group value."""
+
+ """Returns True if the value matches, False otherwise."""
+
+ return self.__value == value
+
+ def GetDisplayText(self):
+ label = self.GetLabel()
+
+ if label != "": return label
+
+ return str(self.GetValue())
+
+ def __eq__(self, other):
+ return ClassGroup.__eq__(self, other) \
+ and isinstance(other, ClassGroupSingleton) \
+ and self.__value == other.__value
+
+ def __repr__(self):
+ return "(" + repr(self.__value) + ", " + ClassGroup.__repr__(self) + ")"
+
+class ClassGroupDefault(ClassGroup):
+ """The default Group. When values do not match any other
+ Group within a Classification, the properties from this
+ class are used."""
+
+ def __init__(self, props = None, label = "", group = None):
+ """Constructor.
+
+ prop -- a ClassGroupProperites object. If prop is None a default
+ set of properties is created.
+
+ label -- a label for this group.
+ """
+
+ ClassGroup.__init__(self, label, props, group)
+
+ def __copy__(self):
+ return ClassGroupDefault(self.GetProperties(), self.GetLabel())
+
+ def __deepcopy__(self, memo):
+ return ClassGroupDefault(label = self.GetLabel(), group = self)
+
+ def Matches(self, value):
+ return True
+
+ def GetDisplayText(self):
+ label = self.GetLabel()
+
+ if label != "": return label
+
+ return _("DEFAULT")
+
+ def __eq__(self, other):
+ return ClassGroup.__eq__(self, other) \
+ and isinstance(other, ClassGroupDefault) \
+ and self.GetProperties() == other.GetProperties()
+
+ def __repr__(self):
+ return "(" + ClassGroup.__repr__(self) + ")"
+
+class ClassGroupRange(ClassGroup):
+ """A Group that represents a range of values that map to the same
+ set of properties."""
+
+ def __init__(self, _range = (0,1), props = None, label = "", group=None):
+ """Constructor.
+
+ The minumum value must be strictly less than the maximum.
+
+ _range -- either a tuple (min, max) where min < max or
+ a Range object
+
+ prop -- a ClassGroupProperites object. If prop is None a default
+ set of properties is created.
+
+ label -- a label for this group.
+ """
+
+ ClassGroup.__init__(self, label, props, group)
+ self.SetRange(_range)
+
+ def __copy__(self):
+ return ClassGroupRange(self.__range,
+ props = self.GetProperties(),
+ label = self.GetLabel())
+
+ def __deepcopy__(self, memo):
+ return ClassGroupRange(copy.copy(self.__range),
+ group = self)
+
+ def GetMin(self):
+ """Return the range's minimum value."""
+ return self.__range.GetRange()[1]
+
+ def SetMin(self, min):
+ """Set the range's minimum value.
+
+ min -- the new minimum. Note that this must be less than the current
+ maximum value. Use SetRange() to change both min and max values.
+ """
+
+ self.SetRange((min, self.__range.GetRange()[2]))
+
+ def GetMax(self):
+ """Return the range's maximum value."""
+ return self.__range.GetRange()[2]
+
+ def SetMax(self, max):
+ """Set the range's maximum value.
+
+ max -- the new maximum. Note that this must be greater than the current
+ minimum value. Use SetRange() to change both min and max values.
+ """
+ self.SetRange((self.__range.GetRange()[1], max))
+
+ def SetRange(self, _range):
+ """Set a new range.
+
+ _range -- Either a tuple (min, max) where min < max or
+ a Range object.
+
+ Raises ValueError on error.
+ """
+
+ if isinstance(_range, Range):
+ self.__range = _range
+ elif isinstance(_range, types.TupleType) and len(_range) == 2:
+ self.__range = Range(("[", _range[0], _range[1], "["))
+ else:
+ raise ValueError()
+
+ def GetRange(self):
+ """Return the range as a string"""
+ return self.__range.string(self.__range.GetRange())
+
+ def GetRangeTuple(self):
+ return self.__range.GetRange()
+
+ def Matches(self, value):
+ """Determine if the given value lies with the current range.
+
+ The following check is used: min <= value < max.
+ """
+
+ return operator.contains(self.__range, value)
+
+ def GetDisplayText(self):
+ label = self.GetLabel()
+
+ if label != "": return label
+
+ return self.__range.string(self.__range.GetRange())
+
+ def __eq__(self, other):
+ return ClassGroup.__eq__(self, other) \
+ and isinstance(other, ClassGroupRange) \
+ and self.__range == other.__range
+
+ def __repr__(self):
+ return "(" + str(self.__range) + ClassGroup.__repr__(self) + ")"
+
+class ClassGroupPattern(ClassGroup):
+ """A Group that is associated with a reg exp pattern."""
+
+ def __init__(self, pattern = "", props = None, label = "", group = None):
+ """Constructor.
+
+ pattern -- the associated pattern.
+
+ props -- a ClassGroupProperites object. If props is None a default
+ set of properties is created.
+
+ label -- a label for this group.
+ """
+ ClassGroup.__init__(self, label, props, group)
+
+ self.SetPattern(pattern)
+
+ def __copy__(self):
+ return ClassGroupPattern(self.GetPattern(),
+ self.GetProperties(),
+ self.GetLabel())
+
+ def __deepcopy__(self, memo):
+ return ClassGroupPattern(self.GetPattern(), group = self)
+
+ def GetPattern(self):
+ """Return the associated pattern."""
+ return self.__pattern
+
+ def SetPattern(self, pattern):
+ """Associate this Group with the given pattern."""
+ self.__pattern = pattern
+
+ def Matches(self, pattern):
+ """Check if the given pattern matches the associated Group pattern."""
+
+ """Returns True if the value matches, False otherwise."""
+
+ if re.match(self.__pattern, pattern):
+ return True
+ else:
+ return False
+
+ def GetDisplayText(self):
+ label = self.GetLabel()
+
+ if label != "": return label
+
+ return str(self.GetPattern())
+
+ def __eq__(self, other):
+ return ClassGroup.__eq__(self, other) \
+ and isinstance(other, ClassGroupPattern) \
+ and self.__pattern == other.__pattern
+
+ def __repr__(self):
+ return "(" + repr(self.__pattern) + ", " + ClassGroup.__repr__(self) + ")"
+
+class ClassGroupMap(ClassGroup):
+ """Currently, this class is not used."""
+
+ FUNC_ID = "id"
+
+ def __init__(self, map_type = FUNC_ID, func = None, prop = None, label=""):
+ ClassGroup.__init__(self, label)
+
+ self.map_type = map_type
+ self.func = func
+
+ if self.func is None:
+ self.func = func_id
+
+ def Map(self, value):
+ return self.func(value)
+
+ def GetProperties(self):
+ return None
+
+ def GetPropertiesFromValue(self, value):
+ pass
+
+ def GetDisplayText(self):
+ return "Map: " + self.map_type
+
+ #
+ # built-in mappings
+ #
+ def func_id(value):
+ return value
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/color.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/color.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/color.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,60 @@
+# Copyright (c) 2001, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 1546 $"
+
+class Color:
+ """An RGB color. RGB values are floats in the range 0.0 .. 1.0
+
+ Color objects should be treated as immutable
+ """
+
+ def __init__(self, red, green, blue):
+ self.red = red
+ self.green = green
+ self.blue = blue
+
+ def hex(self):
+ """Return the color as a HTML/CSS hex code"""
+ return "#%02x%02x%02x" % (255 * self.red,
+ 255 * self.green,
+ 255 * self.blue)
+
+ def __eq__(self, other):
+ """Test equality with other Color objects."""
+ return isinstance(other, Color) \
+ and self.red == other.red \
+ and self.green == other.green \
+ and self.blue == other.blue
+
+ def __ne__(self, other):
+ """Test inequality with other Color objects."""
+ return not self.__eq__(other)
+
+ def __repr__(self):
+ """Return a string of the rgb values"""
+ return "Color(%r, %r, %r)" % (self.red, self.green, self.blue)
+
+class _Transparent:
+ """An object which represents no color."""
+
+ def hex(self):
+ return "None"
+
+ def __eq__(self, other):
+ return isinstance(other, _Transparent)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __repr__(self):
+ return "Transparent"
+
+Transparent = _Transparent()
+Black = Color(0, 0, 0)
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/data.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/data.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/data.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,385 @@
+# Copyright (C) 2003, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Data source abstractions"""
+
+from __future__ import generators
+
+__version__ = "$Revision: 2605 $"
+# $Source$
+# $Id: data.py 2605 2005-04-27 11:04:56Z jan $
+
+import os
+import weakref
+from math import ceil, log
+
+import shapelib
+import shptree
+import table
+import transientdb
+
+from Thuban import _
+
+# Shape type constants
+SHAPETYPE_POLYGON = "polygon"
+SHAPETYPE_ARC = "arc"
+SHAPETYPE_POINT = "point"
+
+# mapping from shapelib shapetype constants to our constants
+shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,
+ shapelib.SHPT_ARC: SHAPETYPE_ARC,
+ shapelib.SHPT_POINT: SHAPETYPE_POINT}
+
+#
+# Raw shape data formats
+#
+
+# Raw data is the same as that returned by the points method.
+RAW_PYTHON = "RAW_PYTHON"
+
+# Raw data is a shapefile. The Shape object will use the shapeid as the
+# raw data.
+RAW_SHAPEFILE = "RAW_SHAPEFILE"
+
+# Raw data in well-known text format
+RAW_WKT = "RAW_WKT"
+
+
+class ShapefileShape:
+
+ """Represent one shape of a shapefile"""
+
+ def __init__(self, shapefile, shapeid):
+ self.shapefile = shapefile
+ self.shapeid = shapeid
+
+ def compute_bbox(self):
+ """
+ Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ """
+ xs = []
+ ys = []
+ for part in self.Points():
+ for x, y in part:
+ xs.append(x)
+ ys.append(y)
+ return (min(xs), min(ys), max(xs), max(ys))
+
+ def ShapeID(self):
+ return self.shapeid
+
+ def Points(self):
+ """Return the coordinates of the shape as a list of lists of pairs"""
+ shape = self.shapefile.read_object(self.shapeid)
+ points = shape.vertices()
+ if self.shapefile.info()[1] == shapelib.SHPT_POINT:
+ points = [points]
+ return points
+
+ def RawData(self):
+ """Return the shape id to use with the shapefile"""
+ return self.shapeid
+
+ def Shapefile(self):
+ """Return the shapefile object"""
+ return self.shapefile
+
+
+class ShapeTable(transientdb.AutoTransientTable):
+
+ """A Table that depends on a ShapefileStore
+
+ Intended use is by the ShapefileStore for the table associated with
+ the shapefiles.
+ """
+
+ def __init__(self, store, db, table):
+ """Initialize the ShapeTable.
+
+ Parameters:
+ store -- the ShapefileStore the table is to depend on
+ db -- The transient database to use
+ table -- the table
+ """
+ transientdb.AutoTransientTable.__init__(self, db, table)
+ self.store = weakref.ref(store)
+
+ def Dependencies(self):
+ """Return a tuple containing the shapestore"""
+ return (self.store(),)
+
+# XXX: (this statement should be kept in mind when re-engeneering)
+#
+# From a desing POV it was wrong to distinguish between table and
+# shapestore. In hindsight the only reason for doing so was that the
+# shapelib has different objects for the shapefile(s) and the dbf file,
+# which of course matches the way the data is organized into different
+# files. So the distinction between shapestore and table is an artifact
+# of the shapefile format. When we added the postgis support we should
+# have adopted the table interface for the entire shape store, making the
+# geometry data an additional column for those shape stores that don't
+# store the geometries in columns in the first place.
+
+class FileShapeStore:
+
+ """The base class to derive any file-based ShapeStore from.
+
+ This class contains all information that is needed by a
+ loader routine to actually load the shapestore.
+ This essentially means that the class contains all required information
+ to save the shapestore specification (i.e. in a .thuban file).
+ """
+
+ def __init__(self, filename, sublayer_name = None):
+ """Initialize the base class with main parameters.
+
+ filename -- the source filename.
+ This filename will be converted to an absolute filename.
+ The filename will be interpreted relative to the .thuban file anyway,
+ but when saving a session we need to compare absolute paths
+ and it's usually safer to always work with absolute paths.
+ sublayer_name -- a string representing a layer within the file shape store.
+ Some file formats support to contain several layers, or
+ at least the ogr library says so.
+ For those filetypes who don't, the sublayer_name can be ignored
+ and by default it is None.
+ """
+ self._filename = os.path.abspath(filename)
+ self._sublayer_name = sublayer_name
+
+ def FileName(self):
+ """Return the filename used to open the shapestore.
+
+ The filename can only be set via __init__ method.
+ """
+ return self._filename
+
+ def FileType(self):
+ """Return the filetype.
+
+ The filetype has to be set in all derived classes.
+ It must be string.
+ Known and used types are: "shapefile"
+ """
+ raise NotImplementedError
+
+ def SublayerName(self):
+ """Return the sublayer_name.
+
+ This could be None if the shapestore type only supports a single
+ layer.
+ """
+ return self._sublayer_name
+
+ # Design/Implementation note:
+ # It is not a good idea to have a implementation for a
+ # "setBoundingBox" or BoundingBox in this base class.
+ # In future this data might change during
+ # a Thuban session and thus can not be kept statically here.
+ # It is expected that for many derived classes the bbox must
+ # be retrieved each time anew.
+
+ def BoundingBox(self):
+ """Return the bounding box of the shapes in the shape store.
+
+ The coordinate system used is whatever was used in the shape store.
+ If the shape store is empty, return None.
+ """
+ raise NotImplementedError
+
+class ShapefileStore(FileShapeStore):
+
+ """Combine a shapefile and the corresponding DBF file into one object"""
+
+ def __init__(self, session, filename):
+ FileShapeStore.__init__(self, filename)
+
+ self.dbftable = table.DBFTable(filename)
+ self._table = ShapeTable(self, session.TransientDB(), self.dbftable)
+ self._bbox = None
+ self._open_shapefile()
+
+ def _open_shapefile(self):
+ self.shapefile = shapelib.ShapeFile(self.FileName())
+ self.numshapes, shapetype, mins, maxs = self.shapefile.info()
+ if self.numshapes:
+ self._bbox = mins[:2] + maxs[:2]
+ else:
+ self._bbox = None
+ self.shapetype = shapelib_shapetypes[shapetype]
+
+ # estimate a good depth for the quad tree. Each depth multiplies
+ # the number of nodes by four, therefore we basically take the
+ # base 4 logarithm of the number of shapes.
+ if self.numshapes < 4:
+ maxdepth = 1
+ else:
+ maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
+
+ self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
+ maxdepth)
+
+ def Table(self):
+ """Return the table containing the attribute data."""
+ return self._table
+
+ def Shapefile(self):
+ """Return the shapefile object"""
+ return self.shapefile
+
+ def FileType(self):
+ """Return the filetype. This is always the string 'shapefile'"""
+ return "shapefile"
+
+ def ShapeType(self):
+ """Return the type of the shapes in the shapestore.
+
+ This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
+ """
+ return self.shapetype
+
+ def RawShapeFormat(self):
+ """Return the raw data format of the shape data, i.e. RAW_SHAPEFILE"""
+ return RAW_SHAPEFILE
+
+ def NumShapes(self):
+ """Return the number of shapes in the shapefile"""
+ return self.numshapes
+
+ def Dependencies(self):
+ """Return the empty tuple.
+
+ The ShapefileStore doesn't depend on anything else.
+ """
+ return ()
+
+ def OrigShapeStore(self):
+ """Return None.
+
+ The ShapefileStore was not derived from another shapestore.
+ """
+ return None
+
+ def BoundingBox(self):
+ """Return the bounding box of the shapes in the shapefile.
+
+ The coordinate system used is whatever was used in the shapefile.
+ If the shapefileis empty, return None.
+ """
+ return self._bbox
+
+ def ShapesInRegion(self, bbox):
+ """Return an iterable over the shapes that overlap the bounding box.
+
+ The bbox parameter should be the bounding box as a tuple in the
+ form (minx, miny, maxx, maxy) in the coordinate system of the
+ shapefile.
+ """
+ # Bind a few globals to locals to make it a bit faster
+ cls = ShapefileShape
+ shapefile = self.shapefile
+
+ left, bottom, right, top = bbox
+ for i in self.shapetree.find_shapes((left, bottom), (right, top)):
+ yield cls(shapefile, i)
+
+ def AllShapes(self):
+ """Return an iterable over the shapes in the shapefile."""
+ for i in xrange(self.NumShapes()):
+ yield ShapefileShape(self.shapefile, i)
+
+ def Shape(self, index):
+ """Return the shape with index index"""
+ return ShapefileShape(self.shapefile, index)
+
+
+class DerivedShapeStore:
+
+ """A ShapeStore derived from other shapestores or tables"""
+
+ def __init__(self, shapestore, table):
+ """Initialize the derived shapestore.
+
+ The arguments are a shapestore for the shapedata and a table for
+ the tabular data.
+
+ Raises ValueError if the number of shapes in the shapestore
+ is different from the number of rows in the table.
+ """
+
+ numShapes = shapestore.Shapefile().info()[0]
+ if numShapes != table.NumRows():
+ raise ValueError(_("Table not compatible with shapestore."))
+
+ self.shapestore = shapestore
+ self.table = table
+
+ def Table(self):
+ """Return the table"""
+ return self.table
+
+ def Shapefile(self):
+ """Return the shapefile of the underlying shapestore"""
+ return self.shapestore.Shapefile()
+
+ def Dependencies(self):
+ """Return a tuple containing the shapestore and the table"""
+ return (self.shapestore, self.table)
+
+ def OrigShapeStore(self):
+ """
+ Return the original shapestore the derived store was instantiated with
+ """
+ return self.shapestore
+
+ def Shape(self, index):
+ """Return the shape with index index"""
+ return self.shapestore.Shape(index)
+
+ def ShapesInRegion(self, bbox):
+ """Return the ids of the shapes that overlap the box.
+
+ This method is simply delegated to the shapestore the
+ DerivedShapeStore was instantiated with.
+ """
+ return self.shapestore.ShapesInRegion(bbox)
+
+ def AllShapes(self):
+ """Return an iterable over the shapes in the shapefile.
+
+ This method is simply delegated to the shapestore the
+ DerivedShapeStore was instantiated with.
+ """
+ return self.shapestore.AllShapes()
+
+ def ShapeType(self):
+ """Return the type of the shapes in the layer.
+
+ This method is simply delegated to the shapestore the
+ DerivedShapeStore was instantiated with.
+ """
+ return self.shapestore.ShapeType()
+
+ def RawShapeFormat(self):
+ """Return the raw data format of the shapes.
+
+ This method is simply delegated to the shapestore the
+ DerivedShapeStore was instantiated with.
+ """
+ return self.shapestore.RawShapeFormat()
+
+ def NumShapes(self):
+ """Return the number of shapes in the shapestore."""
+ return self.shapestore.NumShapes()
+
+ def BoundingBox(self):
+ """Return the bounding box of the shapes in the shapestore.
+
+ This method is simply delegated to the shapestore the
+ DerivedShapeStore was instantiated with.
+ """
+ return self.shapestore.BoundingBox()
Added: packages/thuban/branches/upstream/current/Thuban/Model/extension.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/extension.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/extension.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,92 @@
+# Copyright (c) 2001, 2002 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2355 $"
+
+from Thuban import _
+
+from messages import EXTENSION_CHANGED, EXTENSION_OBJECTS_CHANGED
+
+from base import TitledObject, Modifiable
+
+
+class Extension(TitledObject, Modifiable):
+
+ """Represent a extension. A extension is a package of additional
+ functionality to Thuban and contains a number of Objects
+ that can be freely defined in an extension.
+ Each object must a a TitleObject with additional set "object.name".
+ Furthermore, each object must implement the methods Subscribe,
+ Unsubscribe and Destroy (i.e. derive from Modifiable).
+
+ Extension objects send the following message types:
+
+ EXTENSION_CHANGED -- Something in the extension has changed.
+
+ EXTENSION_OBJECTS_CHANGED -- Something in the objects has changed.
+
+ """
+
+ forwarded_channels = (EXTENSION_CHANGED, EXTENSION_OBJECTS_CHANGED)
+
+ def __init__(self, title):
+ """Initialize the extension."""
+ TitledObject.__init__(self, title)
+ self.objects = []
+
+ def Destroy(self):
+ for object in self.objects:
+ object.Destroy()
+ Modifiable.Destroy(self)
+
+ def AddObject(self, object):
+ self.objects.append(object)
+ for channel in self.forwarded_channels:
+ object.Subscribe(channel, self.forward, channel)
+ self.changed(EXTENSION_OBJECTS_CHANGED, self)
+
+ def RemoveObject(self, object):
+ for channel in self.forwarded_channels:
+ object.Unsubscribe(channel, self.forward, channel)
+ self.layers.remove(layer)
+ self.changed(EXTENSION_OBJECTS_CHANGED, self)
+ object.Destroy()
+
+ def Objects(self):
+ return self.objects
+
+ def HasObjects(self):
+ return len(self.objects) > 0
+
+ def FindObject(self, title):
+ """Find an object by title. If found, return it, else return None."""
+ for object in self.objects:
+ if object.title == title:
+ return object
+ return None
+
+ def forward(self, *args):
+ """Reissue events"""
+ if len(args) > 1:
+ args = (args[-1],) + args[:-1]
+ apply(self.issue, args)
+
+ def WasModified(self):
+ """Return true if something of the extension was modified"""
+ if self.modified:
+ return 1
+ else:
+ return 0
+
+ def UnsetModified(self):
+ """Unset the modified flag of the extension"""
+ Modifiable.UnsetModified(self)
+
+ def TreeInfo(self):
+ return (_("Extension: %s") % self.title,
+ ["%s: %s" % (object.title, object.name)
+ for object in self.objects])
Added: packages/thuban/branches/upstream/current/Thuban/Model/label.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/label.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/label.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,92 @@
+# Copyright (c) 2001, 2002, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2569 $"
+
+from Thuban import _
+
+from messages import CHANGED
+
+from base import TitledObject, Modifiable
+
+ALIGN_CENTER = "center"
+ALIGN_TOP = "top"
+ALIGN_BOTTOM = "bottom"
+ALIGN_LEFT = "left"
+ALIGN_RIGHT = "right"
+ALIGN_BASELINE = "baseline"
+
+class Label:
+
+ """This class repesents a single label.
+
+ The label is defined by its coordinate, the text as well
+ as vertical and horizontal alignment concerning
+ the coordinate.
+ """
+
+ def __init__(self, x, y, text, halign, valign):
+ """Initialize the label with the given parameters."""
+ self.x = x
+ self.y = y
+ self.text = text
+ self.halign = halign
+ self.valign = valign
+
+
+class LabelLayer(TitledObject, Modifiable):
+
+ """This represent a layer holding a number of labels."""
+
+ def __init__(self, title):
+ """Initialize the LabeleLayer.
+
+ Initialization is done with an empty
+ list of labels and set the title to "title".
+ """
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.labels = []
+
+ def Labels(self):
+ """Return a list of all labels."""
+ return self.labels
+
+ def AddLabel(self, x, y, text, halign = ALIGN_LEFT,
+ valign = ALIGN_CENTER):
+ """Add a label at position (x,y) with contents "text".
+
+ This will emit a CHANGED signal.
+ """
+ self.labels.append(Label(x, y, text, halign, valign))
+ self.changed(CHANGED)
+
+ def RemoveLabel(self, index):
+ """Remove the label specified by index.
+
+ This will emit a CHANGED signal.
+ """
+ del self.labels[index]
+ self.changed(CHANGED)
+
+ def ClearLabels(self):
+ """Remove all labels.
+
+ This will emit a CHANGED signal.
+ """
+ del self.labels[:]
+ self.changed(CHANGED)
+
+ def TreeInfo(self):
+ """Return a description of the object.
+
+ A tuple of (title, tupel) describing the contents
+ of the object in a tree-structure is returned.
+ """
+ items = []
+ items.append(_("Number of labels: %d") % len(self.labels))
+ return (_("Label Layer: %s") % self.title, items)
Added: packages/thuban/branches/upstream/current/Thuban/Model/layer.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/layer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/layer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,584 @@
+# Copyright (c) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jonathan Coles <jonathan at intevation.de>
+# Silke Reimer <silke at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2710 $"
+
+import os
+import warnings
+
+from wxproj import point_in_polygon_shape, shape_centroid
+
+from Thuban import _
+
+from messages import LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED, \
+ LAYER_CHANGED, LAYER_SHAPESTORE_REPLACED, CLASS_CHANGED
+
+import classification
+
+from color import Transparent, Black
+from base import TitledObject, Modifiable
+from data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
+from label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
+ ALIGN_LEFT, ALIGN_RIGHT
+
+import resource
+
+from color import Color
+
+shapetype_names = {SHAPETYPE_POINT: "Point",
+ SHAPETYPE_ARC: "Arc",
+ SHAPETYPE_POLYGON: "Polygon"}
+
+class BaseLayer(TitledObject, Modifiable):
+
+ """Base class for the layers."""
+
+ def __init__(self, title, visible = True, projection = None):
+ """Initialize the layer.
+
+ title -- the title
+ visible -- boolean. If true the layer is visible.
+ """
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.visible = visible
+ self.projection = projection
+
+ def Visible(self):
+ """Return true if layer is visible"""
+ return self.visible
+
+ def SetVisible(self, visible):
+ """Set the layer's visibility."""
+ self.visible = visible
+ self.issue(LAYER_VISIBILITY_CHANGED, self)
+
+ def HasClassification(self):
+ """Determine if this layer supports classifications."""
+ return False
+
+ def HasShapes(self):
+ """Determine if this layer supports shapes."""
+ return False
+
+ def GetProjection(self):
+ """Return the layer's projection."""
+ return self.projection
+
+ def SetProjection(self, projection):
+ """Set the layer's projection."""
+ self.projection = projection
+ self.changed(LAYER_PROJECTION_CHANGED, self)
+
+ def Type(self):
+ return "Unknown"
+
+class Layer(BaseLayer):
+
+ """Represent the information of one geodata file (currently a shapefile)
+
+ All children of the layer have the same type.
+
+ A layer has fill and stroke colors. Colors should be instances of
+ Color. They can also be Transparent, indicating no fill or no stroke.
+
+ The layer objects send the following events, all of which have the
+ layer object as parameter:
+
+ TITLE_CHANGED -- The title has changed.
+ LAYER_PROJECTION_CHANGED -- the projection has changed.
+ """
+
+ def __init__(self, title, data, projection = None,
+ fill = Transparent,
+ stroke = Black,
+ lineWidth = 1,
+ visible = True):
+ """Initialize the layer.
+
+ title -- the title
+ data -- datastore object for the shape data shown by the layer
+ projection -- the projection object. Its Inverse method is
+ assumed to map the layer's coordinates to lat/long
+ coordinates
+ fill -- the fill color or Transparent if the shapes are
+ not filled
+ stroke -- the stroke color or Transparent if the shapes
+ are not stroked
+ visible -- boolean. If true the layer is visible.
+
+ colors are expected to be instances of Color class
+ """
+ BaseLayer.__init__(self, title,
+ visible = visible,
+ projection = projection)
+
+ self.__classification = None
+ self.store = None
+
+ self.SetShapeStore(data)
+
+ self.classification_column = None
+ self.SetClassificationColumn(None)
+ self.SetClassification(None)
+
+ self.__classification.SetDefaultLineColor(stroke)
+ self.__classification.SetDefaultLineWidth(lineWidth)
+ self.__classification.SetDefaultFill(fill)
+
+ self.UnsetModified()
+
+ def SetShapeStore(self, store):
+ # Set the classification to None if there is a classification
+ # and the new shapestore doesn't have a table with a suitable
+ # column, i.e one with the same name and type as before
+ # FIXME: Maybe we should keep it the same if the type is
+ # compatible enough such as FIELDTYPE_DOUBLE and FIELDTYPE_INT
+ if self.__classification is not None:
+ columnname = self.classification_column
+ columntype = self.GetFieldType(columnname)
+ table = store.Table()
+ if (columnname is not None
+ and (not table.HasColumn(columnname)
+ or table.Column(columnname).type != columntype)):
+ self.SetClassification(None)
+
+ self.store = store
+
+ self.changed(LAYER_SHAPESTORE_REPLACED, self)
+
+ def ShapeStore(self):
+ return self.store
+
+ def Destroy(self):
+ BaseLayer.Destroy(self)
+ if self.__classification is not None:
+ self.__classification.Unsubscribe(CLASS_CHANGED,
+ self._classification_changed)
+
+ def BoundingBox(self):
+ """Return the layer's bounding box in the intrinsic coordinate system.
+
+ If the layer has no shapes, return None.
+ """
+ return self.store.BoundingBox()
+
+ def LatLongBoundingBox(self):
+ """Return the layer's bounding box in lat/long coordinates.
+
+ Return None, if the layer doesn't contain any shapes.
+ """
+ bbox = self.BoundingBox()
+ if bbox is not None and self.projection is not None:
+ bbox = self.projection.InverseBBox(bbox)
+ return bbox
+
+ def Type(self):
+ return self.ShapeType();
+
+ def ShapesBoundingBox(self, shapes):
+ """Return a bounding box in lat/long coordinates for the given
+ list of shape ids.
+
+ If shapes is None or empty, return None.
+ """
+
+ if shapes is None or len(shapes) == 0: return None
+
+ xs = []
+ ys = []
+
+ for id in shapes:
+ bbox = self.Shape(id).compute_bbox()
+ if self.projection is not None:
+ bbox = self.projection.InverseBBox(bbox)
+ left, bottom, right, top = bbox
+ xs.append(left); xs.append(right)
+ ys.append(bottom); ys.append(top)
+
+ return (min(xs), min(ys), max(xs), max(ys))
+
+
+ def GetFieldType(self, fieldName):
+ if self.store:
+ table = self.store.Table()
+ if table.HasColumn(fieldName):
+ return table.Column(fieldName).type
+ return None
+
+ def HasShapes(self):
+ return True
+
+ def NumShapes(self):
+ """Return the number of shapes in the layer"""
+ return self.store.NumShapes()
+
+ def ShapeType(self):
+ """Return the type of the shapes in the layer.
+
+ The return value is one of the SHAPETYPE_* constants defined in
+ Thuban.Model.data.
+ """
+ return self.store.ShapeType()
+
+ def Shape(self, index):
+ """Return the shape with index index"""
+ return self.store.Shape(index)
+
+ def ShapesInRegion(self, bbox):
+ """Return an iterable over the shapes that overlap the bounding box.
+
+ The bbox parameter should be the bounding box as a tuple in the
+ form (minx, miny, maxx, maxy) in unprojected coordinates.
+ """
+ if self.projection is not None:
+ # Ensure that region lies within the layer's bounding box
+ # Otherwise projection of the region would lead to incorrect
+ # values.
+ clipbbox = self.__mangle_bounding_box(bbox)
+ bbox = self.projection.ForwardBBox(clipbbox)
+ return self.store.ShapesInRegion(bbox)
+
+ def GetClassificationColumn(self):
+ return self.classification_column
+
+ def SetClassificationColumn(self, column):
+ """Set the column to classifiy on, or None. If column is not None
+ and the column does not exist in the table, raise a ValueError.
+ """
+ if column:
+ columnType = self.GetFieldType(column)
+ if columnType is None:
+ raise ValueError()
+ changed = self.classification_column != column
+ self.classification_column = column
+ if changed:
+ self.changed(LAYER_CHANGED, self)
+
+ def HasClassification(self):
+ return True
+
+ def GetClassification(self):
+ return self.__classification
+
+ def SetClassification(self, clazz):
+ """Set the classification used by this layer to 'clazz'
+
+ If 'clazz' is None a default classification is created.
+
+ This issues a LAYER_CHANGED event.
+ """
+
+ if self.__classification is not None:
+ self.__classification.Unsubscribe(CLASS_CHANGED,
+ self._classification_changed)
+
+ if clazz is None:
+ clazz = classification.Classification()
+
+ self.__classification = clazz
+ self.__classification.Subscribe(CLASS_CHANGED,
+ self._classification_changed)
+
+ self._classification_changed()
+
+ def _classification_changed(self):
+ """Called from the classification object when it has changed."""
+ self.changed(LAYER_CHANGED, self)
+
+ def TreeInfo(self):
+ items = []
+
+ items.append(_("Filename: %s") % self.ShapeStore().FileName())
+
+ if self.Visible():
+ items.append(_("Shown"))
+ else:
+ items.append(_("Hidden"))
+ items.append(_("Shapes: %d") % self.NumShapes())
+
+ bbox = self.LatLongBoundingBox()
+ if bbox is not None:
+ items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % tuple(bbox))
+ else:
+ items.append(_("Extent (lat-lon):"))
+ items.append(_("Shapetype: %s") % shapetype_names[self.ShapeType()])
+
+ if self.projection and len(self.projection.params) > 0:
+ items.append((_("Projection"),
+ [str(param) for param in self.projection.params]))
+
+ items.append(self.__classification)
+
+ return (_("Layer '%s'") % self.Title(), items)
+
+ def __mangle_bounding_box(self, bbox):
+ # FIXME: This method doesn't make much sense.
+ # See RT #2845 which effectively says:
+ #
+ # If this method, which was originally called ClipBoundingBox,
+ # is supposed to do clipping it shouldn't return the parameter
+ # unchanged when it lies completely outside of the bounding box.
+ # It would be better to return None and return an empty list in
+ # ShapesInRegion (the only caller) in that case.
+ #
+ # This method was introduced to fix a bug that IIRC had
+ # something todo with projections and bounding boxes containing
+ # NaN or INF when the parameter to ShapesInRegion covered the
+ # entire earth or something similarly large).
+ bminx, bminy, bmaxx, bmaxy = bbox
+ lminx, lminy, lmaxx, lmaxy = self.LatLongBoundingBox()
+ if bminx > lmaxx or bmaxx < lminx:
+ left, right = bminx, bmaxx
+ else:
+ left = max(lminx, bminx)
+ right = min(lmaxx, bmaxx)
+ if bminy > lmaxy or bmaxy < lminy:
+ bottom, top = bminy, bmaxy
+ else:
+ bottom = max(lminy, bminy)
+ top = min(lmaxy, bmaxy)
+
+ return (left, bottom, right, top)
+
+ def GetLabelPosFromShape(self, cmap, shape_index):
+ '''
+ Return the label position parameters (x, y, halign, valign) from the
+ shape object
+ '''
+ proj = cmap.projection
+ if proj is not None:
+ map_proj = proj
+ else:
+ map_proj = None
+ proj = self.projection
+ if proj is not None:
+ layer_proj = proj
+ else:
+ layer_proj = None
+
+ shapetype = self.ShapeType()
+ if shapetype == SHAPETYPE_POLYGON:
+ shapefile = self.ShapeStore().Shapefile().cobject()
+ x, y = shape_centroid(shapefile, shape_index,
+ map_proj, layer_proj, 1, 1, 0, 0)
+ if map_proj is not None:
+ x, y = map_proj.Inverse(x, y)
+ else:
+ shape = self.Shape(shape_index)
+ if shapetype == SHAPETYPE_POINT:
+ x, y = shape.Points()[0][0]
+ else:
+ # assume SHAPETYPE_ARC
+ points = shape.Points()[0]
+ x, y = points[len(points) / 2]
+ if layer_proj is not None:
+ x, y = layer_proj.Inverse(x, y)
+ if shapetype == SHAPETYPE_POINT:
+ halign = ALIGN_LEFT
+ valign = ALIGN_CENTER
+ elif shapetype == SHAPETYPE_POLYGON:
+ halign = ALIGN_CENTER
+ valign = ALIGN_CENTER
+ elif shapetype == SHAPETYPE_ARC:
+ halign = ALIGN_LEFT
+ valign = ALIGN_CENTER
+
+ return (x, y, halign, valign)
+
+
+
+if resource.has_gdal_support():
+ import gdal
+ from gdalconst import GA_ReadOnly
+
+class RasterLayer(BaseLayer):
+
+ MASK_NONE = 0
+ MASK_BIT = 1
+ MASK_ALPHA = 2
+
+ def __init__(self, title, filename, projection = None,
+ visible = True, opacity = 1, masktype = MASK_BIT):
+ """Initialize the Raster Layer.
+
+ title -- title for the layer.
+
+ filename -- file name of the source image.
+
+ projection -- Projection object describing the projection which
+ the source image is in.
+
+ visible -- True is the layer should initially be visible.
+
+ Throws IOError if the filename is invalid or points to a file that
+ is not in a format GDAL can use.
+ """
+
+ BaseLayer.__init__(self, title, visible = visible)
+
+ self.projection = projection
+ self.filename = os.path.abspath(filename)
+
+ self.bbox = -1
+
+ self.mask_type = masktype
+ self.opacity = opacity
+
+ self.image_info = None
+
+ if resource.has_gdal_support():
+ #
+ # temporarily open the file so that GDAL can test if it's valid.
+ #
+ dataset = gdal.Open(self.filename, GA_ReadOnly)
+
+ if dataset is None:
+ raise IOError()
+
+ #
+ # while we have the file, extract some basic information
+ # that we can display later
+ #
+ self.image_info = {}
+
+ self.image_info["nBands"] = dataset.RasterCount
+ self.image_info["Size"] = (dataset.RasterXSize, dataset.RasterYSize)
+ self.image_info["Driver"] = dataset.GetDriver().ShortName
+
+ # store some information about the individual bands
+ # [min_value, max_value]
+ a = self.image_info["BandData"] = []
+
+ for i in range(1, dataset.RasterCount+1):
+ band = dataset.GetRasterBand(i)
+ a.append(band.ComputeRasterMinMax())
+
+ self.UnsetModified()
+
+ def BoundingBox(self):
+ """Return the layer's bounding box in the intrinsic coordinate system.
+
+ If the there is no support for images, or the file cannot
+ be read, or there is no geographics information available, return None.
+ """
+ if not resource.has_gdal_support():
+ return None
+
+ if self.bbox == -1:
+ dataset = gdal.Open(self.filename, GA_ReadOnly)
+ if dataset is None:
+ self.bbox = None
+ else:
+ geotransform = dataset.GetGeoTransform()
+ if geotransform is None:
+ return None
+
+ x = 0
+ y = dataset.RasterYSize
+ left = geotransform[0] + \
+ geotransform[1] * x + \
+ geotransform[2] * y
+
+ bottom = geotransform[3] + \
+ geotransform[4] * x + \
+ geotransform[5] * y
+
+ x = dataset.RasterXSize
+ y = 0
+ right = geotransform[0] + \
+ geotransform[1] * x + \
+ geotransform[2] * y
+
+ top = geotransform[3] + \
+ geotransform[4] * x + \
+ geotransform[5] * y
+
+ self.bbox = (left, bottom, right, top)
+
+ return self.bbox
+
+ def LatLongBoundingBox(self):
+ bbox = self.BoundingBox()
+ if bbox is None:
+ return None
+
+ if self.projection is not None:
+ bbox = self.projection.InverseBBox(bbox)
+
+ return bbox
+
+ def Type(self):
+ return "Image"
+
+ def GetImageFilename(self):
+ return self.filename
+
+ def MaskType(self):
+ """Return True if the mask should be used when rendering the layer."""
+ return self.mask_type
+
+ def SetMaskType(self, type):
+ """Set the type of mask to use.
+
+ type can be one of MASK_NONE, MASK_BIT, MASK_ALPHA
+
+ If the state changes, a LAYER_CHANGED message is sent.
+ """
+ if type not in (self.MASK_NONE, self.MASK_BIT, self.MASK_ALPHA):
+ raise ValueError("type is invalid")
+
+ if type != self.mask_type:
+ self.mask_type = type
+ self.changed(LAYER_CHANGED, self)
+
+ def Opacity(self):
+ """Return the level of opacity used in alpha blending.
+ """
+ return self.opacity
+
+ def SetOpacity(self, op):
+ """Set the level of alpha opacity.
+
+ 0 <= op <= 1.
+
+ The layer is fully opaque when op = 1.
+ """
+ if not (0 <= op <= 1):
+ raise ValueError("op out of range")
+
+ if op != self.opacity:
+ self.opacity = op
+ self.changed(LAYER_CHANGED, self)
+
+ def ImageInfo(self):
+ return self.image_info
+
+ def TreeInfo(self):
+ items = []
+
+ items.append(_("Filename: %s") % self.GetImageFilename())
+
+ if self.Visible():
+ items.append(_("Shown"))
+ else:
+ items.append(_("Hidden"))
+
+ bbox = self.LatLongBoundingBox()
+ if bbox is not None:
+ items.append(_("Extent (lat-lon): (%g, %g, %g, %g)") % bbox)
+ else:
+ items.append(_("Extent (lat-lon):"))
+
+ if self.projection and len(self.projection.params) > 0:
+ items.append((_("Projection"),
+ [str(param) for param in self.projection.params]))
+
+ return (_("Layer '%s'") % self.Title(), items)
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/load.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/load.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/load.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,696 @@
+# Copyright (C) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+# Jonathan Coles <jonathan at intevation.de>
+# Frank Koormann <frank at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with GRASS for details.
+
+"""
+Parser for thuban session files.
+"""
+
+__version__ = "$Revision: 2688 $"
+
+import string, os
+
+import xml.sax
+import xml.sax.handler
+from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
+
+from Thuban import _
+
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
+ FIELDTYPE_STRING
+
+from Thuban.Model.color import Color, Transparent
+
+from Thuban.Model.session import Session
+from Thuban.Model.map import Map
+from Thuban.Model.layer import Layer, RasterLayer
+from Thuban.Model.proj import Projection
+from Thuban.Model.range import Range
+from Thuban.Model.classification import Classification, \
+ ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, \
+ ClassGroupPattern, ClassGroupMap, \
+ ClassGroupProperties
+from Thuban.Model.data import DerivedShapeStore, ShapefileStore
+from Thuban.Model.table import DBFTable
+from Thuban.Model.transientdb import TransientJoinedTable
+
+from Thuban.Model.xmlreader import XMLReader
+import resource
+
+import postgisdb
+
+class LoadError(Exception):
+
+ """Exception raised when the thuban file is corrupted
+
+ Not all cases of corrupted thuban files will lead to this exception
+ but those that are found by checks in the loading code itself are.
+ """
+
+
+class LoadCancelled(Exception):
+
+ """Exception raised to indicate that loading was interrupted by the user"""
+
+
+def parse_color(color):
+ """Return the color object for the string color.
+
+ Color may be either 'None' or of the form '#RRGGBB' in the usual
+ HTML color notation
+ """
+ color = string.strip(color)
+ if color == "None":
+ result = Transparent
+ elif color[0] == '#':
+ if len(color) == 7:
+ r = string.atoi(color[1:3], 16) / 255.0
+ g = string.atoi(color[3:5], 16) / 255.0
+ b = string.atoi(color[5:7], 16) / 255.0
+ result = Color(r, g, b)
+ else:
+ raise ValueError(_("Invalid hexadecimal color specification %s")
+ % color)
+ else:
+ raise ValueError(_("Invalid color specification %s") % color)
+ return result
+
+class AttrDesc:
+
+ def __init__(self, name, required = False, default = "",
+ conversion = None):
+ if not isinstance(name, tuple):
+ fullname = (None, name)
+ else:
+ fullname = name
+ name = name[1]
+ self.name = name
+ self.fullname = fullname
+ self.required = required
+ self.default = default
+ self.conversion = conversion
+
+ # set by the SessionLoader's check_attrs method
+ self.value = None
+
+
+class SessionLoader(XMLReader):
+
+ def __init__(self, db_connection_callback = None,
+ shapefile_callback = None):
+ """Inititialize the Sax handler."""
+ XMLReader.__init__(self)
+
+ self.db_connection_callback = db_connection_callback
+ self.shapefile_callback = shapefile_callback
+ self.theSession = None
+ self.aMap = None
+ self.aLayer = None
+
+ # Map ids used in the thuban file to the corresponding objects
+ # in the session
+ self.idmap = {}
+
+ dispatchers = {
+ 'session' : ("start_session", "end_session"),
+
+ 'dbconnection': ("start_dbconnection", None),
+
+ 'dbshapesource': ("start_dbshapesource", None),
+ 'fileshapesource': ("start_fileshapesource", None),
+ 'derivedshapesource': ("start_derivedshapesource", None),
+ 'filetable': ("start_filetable", None),
+ 'jointable': ("start_jointable", None),
+
+ 'map' : ("start_map", "end_map"),
+ 'projection' : ("start_projection", "end_projection"),
+ 'parameter' : ("start_parameter", None),
+ 'layer' : ("start_layer", "end_layer"),
+ 'rasterlayer' : ("start_rasterlayer", "end_rasterlayer"),
+ 'classification': ("start_classification", "end_classification"),
+ 'clnull' : ("start_clnull", "end_clnull"),
+ 'clpoint' : ("start_clpoint", "end_clpoint"),
+ 'clrange' : ("start_clrange", "end_clrange"),
+ 'clpattern' : ("start_clpattern", "end_clpattern"),
+ 'cldata' : ("start_cldata", "end_cldata"),
+ 'table' : ("start_table", "end_table"),
+ 'labellayer' : ("start_labellayer", None),
+ 'label' : ("start_label", None)}
+
+ # all dispatchers should be used for the 0.8 and 0.9 namespaces too
+ for xmlns in ("http://thuban.intevation.org/dtds/thuban-0.8.dtd",
+ "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd",
+ "http://thuban.intevation.org/dtds/thuban-0.9.dtd",
+ "http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd",
+ "http://thuban.intevation.org/dtds/thuban-1.0rc1.dtd",
+ "http://thuban.intevation.org/dtds/thuban-1.0.0.dtd",
+ "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"):
+ for key, value in dispatchers.items():
+ dispatchers[(xmlns, key)] = value
+
+ XMLReader.AddDispatchers(self, dispatchers)
+
+ def Destroy(self):
+ """Clear all instance variables to cut cyclic references.
+
+ The GC would have collected the loader eventually but it can
+ happen that it doesn't run at all until Thuban is closed (2.3
+ but not 2.2 tries a bit harder and forces a collection when the
+ interpreter terminates)
+ """
+ self.__dict__.clear()
+
+ def start_session(self, name, qname, attrs):
+ self.theSession = Session(self.encode(attrs.get((None, 'title'),
+ None)))
+
+ def end_session(self, name, qname):
+ pass
+
+ def check_attrs(self, element, attrs, descr):
+ """Check and convert some of the attributes of an element
+
+ Parameters:
+ element -- The element name
+ attrs -- The attrs mapping as passed to the start_* methods
+ descr -- Sequence of attribute descriptions (AttrDesc instances)
+
+ Return a dictionary containig normalized versions of the
+ attributes described in descr. The keys of that dictionary are
+ the name attributes of the attribute descriptions. The attrs
+ dictionary will not be modified.
+
+ If the attribute is required, i.e. the 'required' attribute of
+ the descrtiption is true, but it is not in attrs, raise a
+ LoadError.
+
+ If the attribute has a default value and it is not present in
+ attrs, use that default value as the value in the returned dict.
+
+ The value is converted before putting it into the returned dict.
+ The following conversions are available:
+
+ 'filename' -- The attribute is a filename.
+
+ If the filename is a relative name, interpret
+ it relative to the directory containing the
+ .thuban file and make it an absolute name
+
+ 'shapestore' -- The attribute is the ID of a shapestore
+ defined earlier in the .thuban file. Look it
+ up self.idmap
+
+ 'table' -- The attribute is the ID of a table or shapestore
+ defined earlier in the .thuban file. Look it up
+ self.idmap. If it's the ID of a shapestore the
+ value will be the table of the shapestore.
+
+ 'idref' -- The attribute is the id of an object defined
+ earlier in the .thuban file. Look it up self.idmap
+
+ 'ascii' -- The attribute is converted to a bytestring with
+ ascii encoding.
+
+ a callable -- The attribute value is passed to the callable
+ and the return value is used as the converted
+ value
+
+ If no conversion is specified for an attribute it is converted
+ with self.encode.
+ """
+ normalized = {}
+
+ for d in descr:
+ if d.required and not attrs.has_key(d.fullname):
+ raise LoadError("Element %s requires an attribute %r"
+ % (element, d.name))
+ value = attrs.get(d.fullname, d.default)
+
+ if d.conversion in ("idref", "shapesource"):
+ if value in self.idmap:
+ value = self.idmap[value]
+ else:
+ raise LoadError("Element %s requires an already defined ID"
+ " in attribute %r"
+ % (element, d.name))
+ elif d.conversion == "table":
+ if value in self.idmap:
+ value = self.idmap[value]
+ if isinstance(value, ShapefileStore):
+ value = value.Table()
+ else:
+ raise LoadError("Element %s requires an already defined ID"
+ " in attribute %r"
+ % (element, d.name))
+ elif d.conversion == "filename":
+ value = os.path.abspath(os.path.join(self.GetDirectory(),
+ self.encode(value)))
+ elif d.conversion == "ascii":
+ value = value.encode("ascii")
+ elif d.conversion:
+ # Assume it's a callable
+ value = d.conversion(value)
+ else:
+ value = self.encode(value)
+
+ normalized[d.name] = value
+ return normalized
+
+ def open_shapefile(self, filename):
+ """Open shapefile, with alternative path handling.
+
+ If a shapefile cannot be opened and an IOError is raised, check for
+ an alternative. This alternative can be specified interactively by
+ the user or taken from a list of (potential) locations, depending on
+ the callback implementation.
+
+ The alternative is rechecked. If taken from a list the user
+ has to confirm the alternative.
+ """
+
+ # Flag if the alternative path was specified interactively / from list.
+ from_list = 0
+ while 1:
+ try:
+ store = self.theSession.OpenShapefile(filename)
+ if from_list:
+ # A valid path has been guessed from a list
+ # Let the user confirm - or select an alternative.
+ filename, from_list = self.shapefile_callback(
+ filename, "check")
+ if filename is None:
+ # Selection cancelled
+ raise LoadCancelled
+ elif store.FileName() == filename:
+ # Proposed file has been accepted
+ break
+ else:
+ # the filename has been changed, try the new file
+ pass
+ else:
+ break
+ except IOError:
+ if self.shapefile_callback is not None:
+ filename, from_list = self.shapefile_callback(
+ filename,
+ mode = "search",
+ second_try = from_list)
+ if filename is None:
+ raise LoadCancelled
+ else:
+ raise
+ return store
+
+ def start_dbconnection(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("dbtype", True),
+ AttrDesc("host", False, ""),
+ AttrDesc("port", False, ""),
+ AttrDesc("user", False, ""),
+ AttrDesc("dbname", True)])
+ ID = attrs["id"]
+ dbtype = attrs["dbtype"]
+ if dbtype != "postgis":
+ raise LoadError("dbtype %r not supported" % filetype)
+
+ del attrs["id"]
+ del attrs["dbtype"]
+
+ # Try to open the connection and if it fails ask the user for
+ # the correct parameters repeatedly.
+ # FIXME: it would be better not to insist on getting a
+ # connection here. We should handle this more like the raster
+ # images where the layers etc still are created but are not
+ # drawn in case Thuban can't use the data for various reasons
+ while 1:
+ try:
+ conn = postgisdb.PostGISConnection(**attrs)
+ break
+ except postgisdb.ConnectionError, val:
+ if self.db_connection_callback is not None:
+ attrs = self.db_connection_callback(attrs, str(val))
+ if attrs is None:
+ raise LoadCancelled
+ else:
+ raise
+
+ self.idmap[ID] = conn
+ self.theSession.AddDBConnection(conn)
+
+ def start_dbshapesource(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("dbconn", True,
+ conversion = "idref"),
+ AttrDesc("tablename", True,
+ conversion = "ascii"),
+ # id_column and geometry_column were
+ # newly introduced with thuban-1.1.dtd
+ # where they're required. Since we
+ # support the older formats too we
+ # have them optional here.
+ AttrDesc("id_column", False, "gid",
+ conversion = "ascii"),
+ AttrDesc("geometry_column", False,
+ conversion = "ascii")])
+ # The default value of geometry_column to use when instantiating
+ # the db shapestore is None which we currently can't easily use
+ # in check_attrs
+ geometry_column = attrs["geometry_column"]
+ if not geometry_column:
+ geometry_column = None
+ dbopen = self.theSession.OpenDBShapeStore
+ self.idmap[attrs["id"]] = dbopen(attrs["dbconn"], attrs["tablename"],
+ id_column = attrs["id_column"],
+ geometry_column=geometry_column)
+
+ def start_fileshapesource(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("filename", True,
+ conversion = "filename"),
+ AttrDesc("filetype", True)])
+ ID = attrs["id"]
+ filename = attrs["filename"]
+ filetype = attrs["filetype"]
+ if filetype != "shapefile":
+ raise LoadError("shapesource filetype %r not supported" % filetype)
+ self.idmap[ID] = self.open_shapefile(filename)
+
+ def start_derivedshapesource(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("shapesource", True,
+ conversion = "shapesource"),
+ AttrDesc("table", True, conversion="table")])
+ store = DerivedShapeStore(attrs["shapesource"], attrs["table"])
+ self.theSession.AddShapeStore(store)
+ self.idmap[attrs["id"]] = store
+
+ def start_filetable(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("title", True),
+ AttrDesc("filename", True,
+ conversion = "filename"),
+ AttrDesc("filetype")])
+ filetype = attrs["filetype"]
+ if filetype != "DBF":
+ raise LoadError("shapesource filetype %r not supported" % filetype)
+ table = DBFTable(attrs["filename"])
+ table.SetTitle(attrs["title"])
+ self.idmap[attrs["id"]] = self.theSession.AddTable(table)
+
+ def start_jointable(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("id", True),
+ AttrDesc("title", True),
+ AttrDesc("left", True, conversion="table"),
+ AttrDesc("leftcolumn", True),
+ AttrDesc("right", True, conversion="table"),
+ AttrDesc("rightcolumn", True),
+
+ # jointype is required for file
+ # version 0.9 but this attribute
+ # wasn't in the 0.8 version because of
+ # an oversight so we assume it's
+ # optional since we want to handle
+ # both file format versions here.
+ AttrDesc("jointype", False,
+ default="INNER")])
+
+ jointype = attrs["jointype"]
+ if jointype == "LEFT OUTER":
+ outer_join = True
+ elif jointype == "INNER":
+ outer_join = False
+ else:
+ raise LoadError("jointype %r not supported" % jointype )
+ table = TransientJoinedTable(self.theSession.TransientDB(),
+ attrs["left"], attrs["leftcolumn"],
+ attrs["right"], attrs["rightcolumn"],
+ outer_join = outer_join)
+ table.SetTitle(attrs["title"])
+ self.idmap[attrs["id"]] = self.theSession.AddTable(table)
+
+ def start_map(self, name, qname, attrs):
+ """Start a map."""
+ self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
+
+ def end_map(self, name, qname):
+ self.theSession.AddMap(self.aMap)
+ self.aMap = None
+
+ def start_projection(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("name", conversion=self.encode),
+ AttrDesc("epsg", default=None,
+ conversion=self.encode)])
+ self.projection_name = attrs["name"]
+ self.projection_epsg = attrs["epsg"]
+ self.projection_params = [ ]
+
+ def end_projection(self, name, qname):
+ if self.aLayer is not None:
+ obj = self.aLayer
+ elif self.aMap is not None:
+ obj = self.aMap
+ else:
+ assert False, "projection tag out of context"
+ pass
+
+ obj.SetProjection(Projection(self.projection_params,
+ self.projection_name,
+ epsg = self.projection_epsg))
+
+ def start_parameter(self, name, qname, attrs):
+ s = attrs.get((None, 'value'))
+ s = str(s) # we can't handle unicode in proj
+ self.projection_params.append(s)
+
+ def start_layer(self, name, qname, attrs, layer_class = Layer):
+ """Start a layer
+
+ Instantiate a layer of class layer_class from the attributes in
+ attrs which may be a dictionary as well as the normal SAX attrs
+ object and bind it to self.aLayer.
+ """
+ title = self.encode(attrs.get((None, 'title'), ""))
+ filename = attrs.get((None, 'filename'), "")
+ filename = os.path.join(self.GetDirectory(), filename)
+ filename = self.encode(filename)
+ visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
+ fill = parse_color(attrs.get((None, 'fill'), "None"))
+ stroke = parse_color(attrs.get((None, 'stroke'), "#000000"))
+ stroke_width = int(attrs.get((None, 'stroke_width'), "1"))
+ if attrs.has_key((None, "shapestore")):
+ store = self.idmap[attrs[(None, "shapestore")]]
+ else:
+ store = self.open_shapefile(filename)
+
+ self.aLayer = layer_class(title, store,
+ fill = fill, stroke = stroke,
+ lineWidth = stroke_width,
+ visible = visible)
+
+ def end_layer(self, name, qname):
+ self.aMap.AddLayer(self.aLayer)
+ self.aLayer = None
+
+ def start_rasterlayer(self, name, qname, attrs, layer_class = RasterLayer):
+ title = self.encode(attrs.get((None, 'title'), ""))
+ filename = attrs.get((None, 'filename'), "")
+ filename = os.path.join(self.GetDirectory(), filename)
+ filename = self.encode(filename)
+ visible = self.encode(attrs.get((None, 'visible'), "true")) != "false"
+ opacity = float(attrs.get((None, 'opacity'), "1"))
+ masktype = str(attrs.get((None, 'masktype'), "bit"))
+
+ masktypes = {"none": layer_class.MASK_NONE,
+ "bit": layer_class.MASK_BIT,
+ "alpha": layer_class.MASK_ALPHA}
+
+ self.aLayer = layer_class(title, filename,
+ visible = visible,
+ opacity = opacity,
+ masktype = masktypes[masktype])
+
+ def end_rasterlayer(self, name, qname):
+ self.aMap.AddLayer(self.aLayer)
+ self.aLayer = None
+
+ def start_classification(self, name, qname, attrs):
+ # field and field_type are optional because the classification
+ # can also be empty, ie. have only a default.
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("field", False),
+ AttrDesc("field_type", False)])
+
+ field = attrs["field"]
+ fieldType = attrs["field_type"]
+
+ if field == "": return # no need to set classification column.
+
+ dbFieldType = self.aLayer.GetFieldType(field)
+
+ if fieldType != dbFieldType:
+ raise ValueError(_("xml field type differs from database!"))
+
+ # setup conversion routines depending on the kind of data
+ # we will be seeing later on
+ if fieldType == FIELDTYPE_STRING:
+ self.conv = str
+ elif fieldType == FIELDTYPE_INT:
+ self.conv = lambda p: int(float(p))
+ elif fieldType == FIELDTYPE_DOUBLE:
+ self.conv = float
+
+ self.aLayer.SetClassificationColumn(field)
+
+ def end_classification(self, name, qname):
+ pass
+
+ def start_clnull(self, name, qname, attrs):
+ self.cl_group = ClassGroupDefault()
+ self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
+ self.cl_prop = ClassGroupProperties()
+
+ def end_clnull(self, name, qname):
+ self.cl_group.SetProperties(self.cl_prop)
+ self.aLayer.GetClassification().SetDefaultGroup(self.cl_group)
+ del self.cl_group, self.cl_prop
+
+ def start_clpoint(self, name, qname, attrs):
+ attrib_value = attrs.get((None, 'value'), "0")
+
+ field = self.aLayer.GetClassificationColumn()
+ if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
+ value = self.encode(attrib_value)
+ else:
+ value = self.conv(attrib_value)
+ self.cl_group = ClassGroupSingleton(value)
+ self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
+ self.cl_prop = ClassGroupProperties()
+
+
+ def end_clpoint(self, name, qname):
+ self.cl_group.SetProperties(self.cl_prop)
+ self.aLayer.GetClassification().AppendGroup(self.cl_group)
+ del self.cl_group, self.cl_prop
+
+ def start_clrange(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("range", False, None),
+ AttrDesc("min", False, None),
+ AttrDesc("max", False, None)])
+
+ range = attrs['range']
+ # for backward compatibility (min/max are not saved)
+ min = attrs['min']
+ max = attrs['max']
+
+ try:
+ if range is not None:
+ self.cl_group = ClassGroupRange(Range(range))
+ elif min is not None and max is not None:
+ self.cl_group = ClassGroupRange((self.conv(min),
+ self.conv(max)))
+ else:
+ self.cl_group = ClassGroupRange(Range(None))
+
+ except ValueError:
+ raise ValueError(_("Classification range is not a number!"))
+
+ self.cl_group.SetLabel(attrs.get((None, 'label'), ""))
+ self.cl_prop = ClassGroupProperties()
+
+
+ def end_clrange(self, name, qname):
+ self.cl_group.SetProperties(self.cl_prop)
+ self.aLayer.GetClassification().AppendGroup(self.cl_group)
+ del self.cl_group, self.cl_prop
+
+
+ def start_clpattern(self, name, qname, attrs):
+ pattern = attrs.get((None, 'pattern'), "")
+
+ self.cl_group = ClassGroupPattern(self.encode(pattern))
+ self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
+ self.cl_prop = ClassGroupProperties()
+
+ def end_clpattern(self, name, qname):
+ self.cl_group.SetProperties(self.cl_prop)
+ self.aLayer.GetClassification().AppendGroup(self.cl_group)
+ del self.cl_group, self.cl_prop
+
+
+ def start_cldata(self, name, qname, attrs):
+ self.cl_prop.SetLineColor(
+ parse_color(attrs.get((None, 'stroke'), "None")))
+ self.cl_prop.SetLineWidth(
+ int(attrs.get((None, 'stroke_width'), "0")))
+ self.cl_prop.SetSize(int(attrs.get((None, 'size'), "5")))
+ self.cl_prop.SetFill(parse_color(attrs.get((None, 'fill'), "None")))
+
+ def end_cldata(self, name, qname):
+ pass
+
+ def start_labellayer(self, name, qname, attrs):
+ self.aLayer = self.aMap.LabelLayer()
+
+ def start_label(self, name, qname, attrs):
+ attrs = self.check_attrs(name, attrs,
+ [AttrDesc("x", True, conversion = float),
+ AttrDesc("y", True, conversion = float),
+ AttrDesc("text", True),
+ AttrDesc("halign", True,
+ conversion = "ascii"),
+ AttrDesc("valign", True,
+ conversion = "ascii")])
+ x = attrs['x']
+ y = attrs['y']
+ text = attrs['text']
+ halign = attrs['halign']
+ valign = attrs['valign']
+ if halign not in ("left", "center", "right"):
+ raise LoadError("Unsupported halign value %r" % halign)
+ if valign not in ("top", "center", "bottom"):
+ raise LoadError("Unsupported valign value %r" % valign)
+ self.aLayer.AddLabel(x, y, text, halign = halign, valign = valign)
+
+ def characters(self, chars):
+ pass
+
+
+def load_session(filename, db_connection_callback = None,
+ shapefile_callback = None):
+ """Load a Thuban session from the file object file
+
+ The db_connection_callback, if given should be a callable object
+ that can be called like this:
+ db_connection_callback(params, message)
+
+ where params is a dictionary containing the known connection
+ parameters and message is a string with a message why the connection
+ failed. db_connection_callback should return a new dictionary with
+ corrected and perhaps additional parameters like a password or None
+ to indicate that the user cancelled.
+ """
+ handler = SessionLoader(db_connection_callback, shapefile_callback)
+ handler.read(filename)
+
+ session = handler.theSession
+ # Newly loaded session aren't modified
+ session.UnsetModified()
+
+ handler.Destroy()
+
+ return session
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/map.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/map.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/map.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,301 @@
+# Copyright (c) 2001-2003, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2569 $"
+
+from messages import MAP_LAYERS_CHANGED, MAP_PROJECTION_CHANGED, \
+ CHANGED, LAYER_PROJECTION_CHANGED, LAYER_LEGEND_CHANGED, \
+ LAYER_VISIBILITY_CHANGED, LAYER_CHANGED, MAP_STACKING_CHANGED, \
+ MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED
+
+from Thuban import _
+
+from base import TitledObject, Modifiable
+
+from label import LabelLayer
+
+
+class Map(TitledObject, Modifiable):
+
+ """Represent a map.
+
+ A map is a list of layers. Additionally
+ there is a special label layer containing all labels that
+ are defined for the map.
+
+ Map objects send the following message types:
+
+ TITLE_CHANGED -- The title has changed. Parameter: the map.
+
+ MAP_LAYERS_CHANGED -- Layers were added, removed or rearranged.
+ Parameters: the map
+
+ MAP_PROJECTION_CHANGED -- the map's projection has changed.
+ Parameter: the map
+ """
+
+ forwarded_channels = (CHANGED,
+ LAYER_PROJECTION_CHANGED,
+ LAYER_LEGEND_CHANGED,
+ LAYER_CHANGED,
+ LAYER_VISIBILITY_CHANGED)
+
+ def __init__(self, title, projection = None):
+ """Initialize the map."""
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.layers = []
+ self.label_layer = LabelLayer(_("Labels"))
+ self.label_layer.Subscribe(CHANGED, self.forward, MAP_LAYERS_CHANGED)
+ self.projection = projection
+
+ def Destroy(self):
+ """Destroys the map object with all layers including the label layer.
+
+ Calls Modifiable. Destroy first since it will call
+ Publisher.Destroy which removes all subscriptions. Otherwise
+ clearing the layers results in messages to be sent which can
+ cause problems.
+ """
+ Modifiable.Destroy(self)
+ self.ClearLayers()
+ self.label_layer.Unsubscribe(CHANGED, self.forward, MAP_LAYERS_CHANGED)
+ self.label_layer.Destroy()
+
+ def AddLayer(self, layer):
+ """Append layer to the map on top of all."""
+ self.layers.append(layer)
+ self.subscribe_layer_channels(layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_LAYERS_ADDED, self)
+
+ def RemoveLayer(self, layer):
+ """Remove layer from the map.
+
+ This can not be applied for the label layer of the map.
+ """
+ self.unsubscribe_layer_channels(layer)
+ self.layers.remove(layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_LAYERS_REMOVED, self)
+ layer.Destroy()
+
+ def CanRemoveLayer(self, layer):
+ """Return true if the layer can be deleted.
+
+ The default implementation always returns 1. Derived classes
+ should override this method if they have e.g. special layers
+ that the user should not be able to remove.
+ """
+ return 1
+
+ def ClearLayers(self):
+ """Delete all layers and also remove all labels from the label layer.
+ """
+ for layer in self.layers:
+ self.unsubscribe_layer_channels(layer)
+ layer.Destroy()
+ del self.layers[:]
+ self.label_layer.ClearLabels()
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_LAYERS_REMOVED, self)
+
+ def subscribe_layer_channels(self, layer):
+ """Subscribe to some of layer's channels."""
+ for channel in self.forwarded_channels:
+ layer.Subscribe(channel, self.forward, channel)
+
+ def unsubscribe_layer_channels(self, layer):
+ """Unsubscribe to some of layer's channels."""
+ for channel in self.forwarded_channels:
+ layer.Unsubscribe(channel, self.forward, channel)
+
+ def LabelLayer(self):
+ """Return the Map's label layer"""
+ return self.label_layer
+
+ def Layers(self):
+ """Return the list of layers contained in the map.
+
+ The list does not include the label layer which
+ can be retrieved by a separate method."""
+ return self.layers
+
+ def HasLayers(self):
+ """Information whether this map has layers.
+
+ Returns true if the map has at least one layer other
+ than the label layer."""
+ return len(self.layers) > 0
+
+ def MoveLayerToTop(self, layer):
+ """Put the layer on top of the layer stack.
+
+ This can not be applied to the label layer.
+
+ If the layer is already at the top do nothing. If the stacking
+ order has been changed, issue a MAP_LAYERS_CHANGED message.
+ """
+ index = self.layers.index(layer)
+ if index < len(self.layers) - 1:
+ del self.layers[index]
+ self.layers.append(layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_STACKING_CHANGED, self)
+
+ def RaiseLayer(self, layer):
+ """Swap the layer with the one above it.
+
+ This does not apply to the label layer.
+
+ If the layer is already at the top do nothing. If the stacking
+ order has been changed, issue a MAP_LAYERS_CHANGED message.
+ """
+ index = self.layers.index(layer)
+ if index < len(self.layers) - 1:
+ del self.layers[index]
+ self.layers.insert(index + 1, layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_STACKING_CHANGED, self)
+
+ def LowerLayer(self, layer):
+ """Swap the layer with the one below it.
+
+ This does not apply to the label layer.
+
+ If the layer is already at the bottom do nothing. If the
+ stacking order has been changed, issue a MAP_LAYERS_CHANGED message.
+ """
+ index = self.layers.index(layer)
+ if index > 0:
+ del self.layers[index]
+ self.layers.insert(index - 1, layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_STACKING_CHANGED, self)
+
+ def MoveLayerToBottom(self, layer):
+ """Put the layer at the bottom of the stack.
+
+ This does not apply to the label layer.
+
+ If the layer is already at the bottom do nothing. If the
+ stacking order has been changed, issue a MAP_LAYERS_CHANGED message.
+ """
+ index = self.layers.index(layer)
+ if index > 0:
+ del self.layers[index]
+ self.layers.insert(0, layer)
+ self.changed(MAP_LAYERS_CHANGED, self)
+ self.changed(MAP_STACKING_CHANGED, self)
+
+ def BoundingBox(self):
+ """Return the bounding box of the map in Lat/Lon coordinates.
+
+ The label layer is not considered for the computation of the
+ bounding box.
+
+ Return None if there are no layers (except the label layer) or
+ no layer contains any shapes.
+ """
+ if not self.layers:
+ return None
+ llx = []
+ lly = []
+ urx = []
+ ury = []
+ for layer in self.layers:
+ # the layer's bbox may be None if it doesn't have any shapes
+ bbox = layer.LatLongBoundingBox()
+ if bbox is not None:
+ left, bottom, right, top = bbox
+ llx.append(left)
+ lly.append(bottom)
+ urx.append(right)
+ ury.append(top)
+
+ # check whether there were any empty layers.
+ if llx:
+ return (min(llx), min(lly), max(urx), max(ury))
+ else:
+ return None
+
+ def ProjectedBoundingBox(self):
+ """Return the bounding box of the map in projected coordinates.
+
+ The label layer is not considered for the computation of the
+ bounding box.
+
+ Return None if there are no layers (except the label layer) or
+ no layer contains any shapes.
+ """
+ # This simply returns the rectangle given by the projected
+ # corners of the non-projected bbox.
+ bbox = self.BoundingBox()
+ if bbox is not None and self.projection is not None:
+ bbox = self.projection.ForwardBBox(bbox)
+ return bbox
+
+ def GetProjection(self):
+ """Return the projection of the map."""
+ return self.projection
+
+ def SetProjection(self, projection):
+ """Set the projection of the map.
+
+ Issue a MAP_PROJECTION_CHANGED message.
+ """
+ old_proj = self.projection
+ self.projection = projection
+ self.changed(MAP_PROJECTION_CHANGED, self, old_proj)
+
+ def forward(self, *args):
+ """Reissue events"""
+ if len(args) > 1:
+ args = (args[-1],) + args[:-1]
+ apply(self.issue, args)
+
+ def WasModified(self):
+ """Return true if the map or one of the layers was modified"""
+ if self.modified:
+ return 1
+ else:
+ for layer in self.layers:
+ if layer.WasModified():
+ return 1
+ return self.label_layer.WasModified()
+
+ def UnsetModified(self):
+ """Unset the modified flag of the map and the layers"""
+ Modifiable.UnsetModified(self)
+ for layer in self.layers:
+ layer.UnsetModified()
+ self.label_layer.UnsetModified()
+
+ def TreeInfo(self):
+ """Return a description of the object.
+
+ A tuple of (title, tupel) describing the contents
+ of the object in a tree-structure is returned.
+ """
+ items = []
+ if self.BoundingBox() != None:
+ items.append(_("Extent (lat-lon): (%g, %g, %g, %g)")
+ % self.BoundingBox())
+ if self.projection and len(self.projection.params) > 0:
+ items.append(_("Extent (projected): (%g, %g, %g, %g)")
+ % self.ProjectedBoundingBox())
+ items.append((_("Projection"),
+ [str(param)
+ for param in self.projection.params]))
+
+ layers = self.layers[:]
+ layers.reverse()
+ items.extend(layers)
+ items.append(self.label_layer)
+
+ return (_("Map: %s") % self.title, items)
Added: packages/thuban/branches/upstream/current/Thuban/Model/messages.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/messages.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/messages.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,53 @@
+# Copyright (c) 2001, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Define the message types used by the classes implementing Thuban's data
+model. The messages types are simply strings. The message system itself
+is implemented in Thuban.Lib.connector.
+"""
+__version__ = "$Revision: 1823 $"
+
+# Common message types
+TITLE_CHANGED = "TITLE_CHANGED"
+CHANGED = "CHANGED"
+
+# ProjFile message types
+PROJECTION_ADDED = "PROJECTION_ADDED"
+PROJECTION_REPLACED = "PROJECTION_REPLACED"
+PROJECTION_REMOVED = "PROJECTION_REMOVED"
+
+# classification specific message types
+CLASS_CHANGED = "CLASS_CHANGED"
+
+# layer specific message types
+LAYER_PROJECTION_CHANGED = "LAYER_PROJECTION_CHANGED"
+LAYER_LEGEND_CHANGED = "LAYER_LEGEND_CHANGED"
+LAYER_VISIBILITY_CHANGED = "LAYER_VISIBILITY_CHANGED"
+LAYER_CHANGED = "LAYER_CHANGED"
+LAYER_SHAPESTORE_REPLACED = "LAYER_SHAPESTORE_REPLACED"
+
+# Map specific message types
+MAP_STACKING_CHANGED = "MAP_STACKING_CHANGED"
+MAP_LAYERS_CHANGED = "MAP_LAYERS_CHANGED"
+MAP_LAYERS_ADDED = "MAP_LAYERS_ADDED"
+MAP_LAYERS_REMOVED = "MAP_LAYERS_REMOVED"
+MAP_PROJECTION_CHANGED = "MAP_PROJECTION_CHANGED"
+
+# Extension specific message types
+EXTENSION_CHANGED = "EXTENSION_CHANGED"
+EXTENSION_OBJECTS_CHANGED = "EXTENSION_OBJECTS_CHANGED"
+
+# Session specific message types
+MAPS_CHANGED = "MAPS_CHANGED"
+EXTENSIONS_CHANGED = "EXTENSIONS_CHANGED"
+FILENAME_CHANGED = "FILENAME_CHANGED"
+
+TABLE_REMOVED = "TABLE_REMOVED"
+
+DBCONN_ADDED = "DBCONN_ADDED"
+DBCONN_REMOVED = "DBCONN_REMOVED"
Added: packages/thuban/branches/upstream/current/Thuban/Model/postgisdb.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/postgisdb.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/postgisdb.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,700 @@
+# Copyright (C) 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Martin Mueller <mmueller at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Basic interface to a PostGIS database"""
+
+from __future__ import generators
+
+try:
+ import psycopg
+except ImportError:
+ psycopg = None
+
+import table
+import wellknowntext
+
+from data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT, RAW_WKT
+
+def has_postgis_support():
+ """Return whether this Thuban instance supports PostGIS connections
+
+ Having PostGIS support means that the psycopg module can be
+ imported.
+ """
+ return psycopg is not None
+
+def psycopg_version():
+ return psycopg.__version__
+
+if psycopg is not None:
+ # type_map maps psycopg type objects. It's a list of pairs since
+ # the psycopg type objects are unhashable.
+ type_map = [(psycopg.STRING, table.FIELDTYPE_STRING),
+ (psycopg.INTEGER, table.FIELDTYPE_INT),
+ (psycopg.ROWID, table.FIELDTYPE_INT),
+ (psycopg.FLOAT, table.FIELDTYPE_DOUBLE)]
+
+ # _raw_type_map maps the postgresql type constants to Thuban type
+ # constants. This is very low level and postgresql specific and
+ # should be used only when necessary.
+ _raw_type_map = {}
+ def _fill_raw_type_map():
+ for psycopg_type, thuban_type in type_map:
+ for value in psycopg_type.values:
+ _raw_type_map[value] = thuban_type
+ _fill_raw_type_map()
+
+
+def quote_identifier(ident):
+ """Return a quoted version of the identifier ident.
+
+ The return value is a string that can be put directly into an SQL
+ statement. The quoted identifier is surrounded by double quotes and
+ any double quotes already in the input value are converted to two
+ double quotes. Examples:
+
+ >>> quote_identifier("abc\"def")
+ '"abc""def"'
+ >>> quote_identifier("abc def")
+ '"abc def"'
+ """
+ return '"' + '""'.join(ident.split('"')) + '"'
+
+
+class ConnectionError(Exception):
+
+ """Class for exceptions occurring when establishing a Databse connection"""
+
+
+class PostGISConnection:
+
+ """Represent a PostGIS database
+
+ A PostGISConnection instance has the following public attributes:
+
+ dbname -- The name of the database
+ host, port -- Host and port to connect to
+ user -- The user name to connect as.
+
+ All of these attributes are strings and may be empty strings to
+ indicate default values.
+ """
+
+ def __init__(self, dbname, host="", user="", password="", dbtype="",
+ port=""):
+ self.dbname = dbname
+ self.host = host
+ self.port = port
+ self.user = user
+ self.password = password
+ self.dbtype = dbtype
+ self.connect()
+
+ def connect(self):
+ """Internal: Establish the database connection"""
+ params = []
+ for name in ("host", "port", "dbname", "user", "password"):
+ val = getattr(self, name)
+ if val:
+ params.append("%s=%s" % (name, val))
+ try:
+ self.connection = psycopg.connect(" ".join(params))
+ except psycopg.OperationalError, val:
+ raise ConnectionError(str(val))
+
+ # Use autocommit mode. For simple reading of the database it's
+ # sufficient and we don't have to care much about error
+ # handling. Without autocommit, an errors during a cursor's
+ # execute method requires a rollback on the connection,
+ # otherwise later queries with the same or other cursors sharing
+ # the same connection will lead to further errors ("ERROR:
+ # current transaction is aborted, commands ignored until end of
+ # transaction block")
+ self.connection.autocommit()
+
+ # determine the OID for the geometry type. This is PostGIS
+ # specific.
+ cursor = self.connection.cursor()
+ cursor.execute("SELECT OID, typname FROM pg_type WHERE"
+ +" typname = 'geometry'")
+ row = cursor.fetchone()
+ self.connection.commit()
+ if row is not None:
+ self.geometry_type = row[0]
+ else:
+ raise ValueError("Can't determine postgres type of geometries")
+
+ def BriefDescription(self):
+ """Return a brief, one-line description of the connection
+
+ The return value is suitable for a list box of all database
+ connections.
+ """
+ return ("postgis://%(user)s@%(host)s:%(port)s/%(dbname)s"
+ % self.__dict__)
+
+ def MatchesParameters(self, parameters):
+ """Return whether the connection matches the dictionary of parameters
+
+ Return whether instatiating the connection with the given
+ parameters would establish essentially the same connection as
+ self. The connection is essentially the same if the same
+ database (identified by host, port and databasename) is accessed
+ as the same user.
+ """
+ return (parameters["host"] == self.host
+ and parameters["port"] == self.port
+ and parameters["dbname"] == self.dbname
+ and parameters["user"] == self.user)
+
+ def Close(self):
+ """Close the database connection"""
+ self.connection.close()
+
+ def GeometryTables(self):
+ """Return a list with the names of all tables with a geometry column"""
+
+ # The query is basically taken from the psql v. 7.2.1. When
+ # started with -E it prints the queries used for internal
+ # commands such as \d, which does mostly what we need here.
+ cursor = self.connection.cursor()
+ cursor.execute("SELECT c.relname FROM pg_class c"
+ " WHERE c.relkind IN ('r', 'v')"
+ # Omit the system tables
+ " AND c.relname !~ '^pg_'"
+ # Omit the special PostGIS tables
+ " AND c.relname NOT IN ('geometry_columns',"
+ " 'spatial_ref_sys')"
+ " AND %d in (SELECT a.atttypid FROM pg_attribute a"
+ " WHERE a.attrelid = c.oid)"
+ " ORDER BY c.relname;", (self.geometry_type,))
+ result = [row[0] for row in cursor.fetchall()]
+ self.connection.commit()
+ return result
+
+ def table_columns(self, tablename):
+ """Experimental: return information about the columns of a table
+
+ Return value is a list of (name, type) pairs where name is the
+ name of the column and type either one of the field type columns
+ or the string 'geometry' indicating a geometry column.
+
+ The intended use of this method is for table selection dialogs
+ which need to determine which columns are usable as id or
+ geometry columns respectively. Suitable id columns will have
+ type FIELDTYPE_INT and geometry columns will have 'geometry'.
+ """
+ result = []
+ cursor = self.connection.cursor()
+
+ # This query is taken basically from the \d command of psql
+ # 7.2.1
+ cursor.execute("SELECT a.attname, a.atttypid, a.attnum"
+ " FROM pg_class c, pg_attribute a"
+ " WHERE c.relname = %s AND a.attrelid = c.oid"
+ " ORDER BY a.attnum;", (tablename,))
+
+ for row in cursor.fetchall():
+ col_name, col_type, col_attnum = row
+ col = None
+ if col_attnum < 1:
+ # It's a system column. Only the OID is interesting
+ # here
+ if col_name == "oid":
+ col = (col_name, _raw_type_map[col_type])
+ else:
+ # If it's an integer
+ thuban_type = _raw_type_map.get(col_type)
+ if thuban_type is not None:
+ col = (col_name, thuban_type)
+ elif row[1] == self.geometry_type:
+ col = (col_name, "geometry")
+ if col is not None:
+ result.append(col)
+
+ return result
+
+ def cursor(self):
+ """Return a DB API 2.0 cursor for the database"""
+ return self.connection.cursor()
+
+
+
+class PostGISColumn:
+
+ """Column description for a PostGISTable
+
+ In addition to the normal column object attributes name, type and
+ index, PostGISColumn objects have a quoted_name attribute which
+ contains a quoted version of name for use in SQL statements. The
+ quoted_name attribute is mainly intended for internal use by the
+ PostGISTable class.
+ """
+
+ def __init__(self, name, type, index):
+ self.name = name
+ self.quoted_name = quote_identifier(name)
+ self.type = type
+ self.index = index
+
+
+class PostGISTable:
+
+ """A Table in a PostGIS database
+
+ A PostgreSQL table may contain columns with types not (yet)
+ supported by Thuban. Instances of this class ignore those columns
+ and pretend they don't exist, i.e. they won't show up in the column
+ descriptions returned by Columns() and other methods.
+ """
+
+ def __init__(self, db, tablename, id_column = None):
+ """Initialize the PostGISTable.
+
+ The db parameter should be an instance of PostGISConnection and
+ tablename the name of a table in the database represented by db.
+
+ The id_column parameter should be the name of a column in the
+ table that can be used to identify rows. The column must have
+ the type integer and be unique and not null.
+
+ For backwards compatibility reasons, the id_column parameter is
+ optional. If not given the table must have a column called
+ 'gid' which is used as the id_column. New code should always
+ provide this parameter.
+ """
+ self.db = db
+ self.tablename = tablename
+ # Tablename quoted for use in SQL statements.
+ self.quoted_tablename = quote_identifier(tablename)
+
+ if not id_column:
+ id_column = "gid"
+ self.id_column = id_column
+ # id column name quoted for use in SQL statements.
+ self.quoted_id_column = quote_identifier(id_column)
+
+ # Map column names and indices to column objects.
+ self.column_map = {}
+
+ self._fetch_table_information()
+
+ def _fetch_table_information(self):
+ """Internal: Update information about the table"""
+ self.columns = []
+ cursor = self.db.cursor()
+ cursor.execute("SELECT * FROM %s WHERE 0=1" % self.quoted_tablename)
+ description = cursor.description
+
+ for i in range(len(description)):
+ col = self._create_col_from_description(i, description[i])
+ if col is not None:
+ self.columns.append(col)
+
+ for col in self.columns:
+ self.column_map[col.name] = col
+ self.column_map[col.index] = col
+
+ # Build query string for ReadRowAsDict
+ self.query_stmt = ("SELECT %s from %s"
+ % (", ".join([col.quoted_name
+ for col in self.columns]),
+ self.quoted_tablename))
+
+ def _create_col_from_description(self, index, description):
+ """Return the column object for the column described by description
+
+ The parameter index is the index of the column. The description
+ is a sequence taken from the cursor's description attribute for
+ the column. That means description[0] is the name of the column
+ and description[1] the type.
+
+ Return None if the column can't be represented for some reason,
+ e.g. because its type is not yet supported or needs to be
+ treated in some special way. Derived classes may extend this
+ method.
+ """
+ for pgtyp, tabletyp in type_map:
+ if pgtyp == description[1]:
+ return PostGISColumn(description[0], tabletyp,
+ len(self.columns))
+ return None
+
+ def DBConnection(self):
+ """Return the dbconnection used by the table"""
+ return self.db
+
+ def IDColumn(self):
+ """Return the column description object for the id column.
+
+ If the oid column was used as the id column, the return value is
+ not one of the regular column objects that would be returned by
+ e.g. the Column() method, but it still has meaningful name
+ attribute.
+ """
+ if self.id_column == "oid":
+ return PostGISColumn(self.id_column, table.FIELDTYPE_INT, None)
+ return self.column_map[self.id_column]
+
+ def TableName(self):
+ """Return the name of the table in the database"""
+ return self.tablename
+
+ def Title(self):
+ """Return the title of the table.
+
+ The title is currently fixed and equal to the tablename
+ """
+ return self.tablename
+
+ def Dependencies(self):
+ """Return an empty tuple because a PostGISTable depends on nothing else
+ """
+ return ()
+
+ def NumColumns(self):
+ return len(self.columns)
+
+ def Columns(self):
+ return self.columns
+
+ def Column(self, col):
+ return self.column_map[col]
+
+ def HasColumn(self, col):
+ return self.column_map.has_key(col)
+
+ def NumRows(self):
+ cursor = self.db.cursor()
+ cursor.execute("SELECT count(*) FROM %s" % self.quoted_tablename)
+ return cursor.fetchone()[0]
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id"""
+ cursor = self.db.cursor()
+ cursor.execute("SELECT count(*) FROM %s WHERE %s < %d;"
+ % (self.quoted_tablename, self.quoted_id_column, gid))
+ return cursor.fetchone()[0]
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal"""
+ cursor = self.db.cursor()
+ cursor.execute("SELECT %s FROM %s LIMIT 1 OFFSET %d;"
+ % (self.quoted_id_column, self.quoted_tablename, num))
+ return cursor.fetchone()[0]
+
+ def ReadRowAsDict(self, row, row_is_ordinal = 0):
+ cursor = self.db.cursor()
+ if row_is_ordinal:
+ stmt = self.query_stmt + " LIMIT 1 OFFSET %d" % row
+ else:
+ stmt = self.query_stmt + " WHERE %s = %d" % (self.quoted_id_column,
+ row)
+ cursor.execute(stmt)
+ result = {}
+ for col, value in zip(self.columns, cursor.fetchone()):
+ result[col.name] = value
+ return result
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ cursor = self.db.cursor()
+ if row_is_ordinal:
+ stmt = ("SELECT %s FROM %s LIMIT 1 OFFSET %d" %
+ (self.column_map[col].quoted_name, self.quoted_tablename,
+ row))
+ else:
+ stmt = ("SELECT %s FROM %s WHERE %s = %d" %
+ (self.column_map[col].quoted_name, self.quoted_tablename,
+ self.quoted_id_column, row))
+ cursor.execute(stmt)
+ return cursor.fetchone()[0]
+
+ def ValueRange(self, col):
+ cursor = self.db.cursor()
+ name = self.column_map[col].quoted_name
+ cursor.execute("SELECT min(%s), max(%s) FROM %s" %
+ (name, name, self.quoted_tablename))
+ return tuple(cursor.fetchone())
+
+ def UniqueValues(self, col):
+ cursor = self.db.cursor()
+ name = self.column_map[col].quoted_name
+ cursor.execute("SELECT %s FROM %s GROUP BY %s" %
+ (name, self.quoted_tablename, name))
+ return [row[0] for row in cursor.fetchall()]
+
+ def SimpleQuery(self, left, comparison, right):
+ if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
+ raise ValueError("Comparison operator %r not allowed" % comparison)
+
+ if comparison == "==":
+ comparison = "="
+
+ if isinstance(right, PostGISColumn):
+ right_template = right.quoted_name
+ params = ()
+ else:
+ right_template = "%s"
+ params = (right,)
+
+ query = "SELECT %s FROM %s WHERE %s %s %s ORDER BY %s;" \
+ % (self.quoted_id_column, self.quoted_tablename,
+ left.quoted_name, comparison, right_template,
+ self.quoted_id_column)
+
+ cursor = self.db.cursor()
+ cursor.execute(query, params)
+ result = []
+ while 1:
+ row = cursor.fetchone()
+ if row is None:
+ break
+ result.append(row[0])
+ return result
+
+
+class PostGISShape:
+
+ def __init__(self, shapeid, data):
+ self.shapeid = shapeid
+ self.data = data
+
+ def compute_bbox(self):
+ """
+ Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
+ """
+ xs = []
+ ys = []
+ for part in self.Points():
+ for x, y in part:
+ xs.append(x)
+ ys.append(y)
+ return (min(xs), min(ys), max(xs), max(ys))
+
+ def ShapeID(self):
+ return self.shapeid
+
+ def Points(self):
+ return wellknowntext.parse_wkt_thuban(self.data)
+
+ def RawData(self):
+ return self.data
+
+
+shapetype_map = {"POLYGON": SHAPETYPE_POLYGON,
+ "MULTIPOLYGON": SHAPETYPE_POLYGON,
+ "LINESTRING": SHAPETYPE_ARC,
+ "MULTILINESTRING": SHAPETYPE_ARC,
+ "POINT": SHAPETYPE_POINT}
+
+
+class PostGISShapeStore(PostGISTable):
+
+ """Shapestore interface to a table in a PostGIS database"""
+
+ def __init__(self, db, tablename, id_column = "gid",
+ geometry_column = None):
+ """Initialize the PostGISShapeStore.
+
+ The db parameter should be an instance of PostGISConnection and
+ tablename the name of a table in the database represented by db.
+
+ The id_column parameter should be the name of a column in the
+ table that can be used to identify rows. The column must have
+ the type integer and be unique and not null.
+
+ The geometry_column paramter, if given, should be the name of
+ the geometry column to use. If the name given is not a geometry
+ column, raise a ValueError.
+
+ If no geometry_column is given, the table must have exactly one
+ geometry column. If it has more than one and the
+ geometry_column is not given, a ValueError will be raised.
+ """
+ self.geometry_column = geometry_column
+ self.geometry_column_was_given = geometry_column is not None
+ PostGISTable.__init__(self, db, tablename, id_column)
+
+ # For convenience, we have a quoted version of the geometry
+ # column in self.quoted_geo_col
+ self.quoted_geo_col = quote_identifier(self.geometry_column)
+
+ def _fetch_table_information(self):
+ """Extend inherited method to retrieve the SRID and shape type"""
+ PostGISTable._fetch_table_information(self)
+
+ # First, try to get it from the geometry_columns table.
+ cursor = self.db.cursor()
+ cursor.execute("SELECT srid, type FROM geometry_columns"
+ " WHERE f_table_name = %s AND f_geometry_column=%s",
+ (self.tablename, self.geometry_column))
+ row = cursor.fetchone()
+ if row is not None:
+ self.srid = row[0]
+ self.shape_type = shapetype_map.get(row[1])
+ return
+
+ # The table is probably really a view and thus not in
+ # geometry_columns. Use a different approach
+ cursor = self.db.cursor()
+ cursor.execute("SELECT DISTINCT SRID(%s) FROM %s;" %
+ (quote_identifier(self.geometry_column),
+ self.tablename))
+ row = cursor.fetchone()
+ if row is not None:
+ self.srid = row[0]
+ # Try to see whether there's another one
+ row = cursor.fetchone()
+ if row is not None:
+ # There are at least two different srids. We don't
+ # support that
+ self.srid = None
+
+ cursor = self.db.cursor()
+ cursor.execute("SELECT DISTINCT GeometryType(%s) FROM %s;"
+ % (quote_identifier(self.geometry_column),
+ self.tablename))
+ row = cursor.fetchone()
+ if row is not None:
+ self.shape_type = shapetype_map.get(row[0])
+ # Try to see whether there's another one
+ row = cursor.fetchone()
+ if row is not None:
+ # There are at least two different srids. We don't
+ # support that
+ self.shape_type = None
+
+ def _create_col_from_description(self, index, description):
+ """Extend the inherited method to find geometry columns
+
+ If the column indicated by the parameters is a geometry column,
+ record its name in self.geometry_column and a quoted version in
+ self.quoted_geo_col. In any case return the return value of the
+ inherited method.
+ """
+ col = PostGISTable._create_col_from_description(self, index,
+ description)
+ col_name, col_type = description[:2]
+ if self.geometry_column_was_given:
+ if (col_name == self.geometry_column
+ and col_type != self.db.geometry_type):
+ raise TypeError("Column %s in %s is not a geometry column"
+ % (self.geometry_column, self.tablename))
+ else:
+ if col is None:
+ if description[1] == self.db.geometry_type:
+ # The column is a geometry column. If the name of
+ # the geometry column was not given to the
+ # constructor, and we encounter two geometry
+ # columns, raise a value error
+ if self.geometry_column is None:
+ self.geometry_column = description[0]
+ else:
+ raise TypeError("Table %s has two geometry columns"
+ " and no column name was given"
+ % (self.tablename,))
+ return col
+
+ def Table(self):
+ """Return self since a PostGISShapeStore is its own table."""
+ return self
+
+ def OrigShapeStore(self):
+ """Return None since the PostGISShapeStore is not derived from another
+ """
+ return None
+
+ def GeometryColumn(self):
+ """Return the column description object for the geometry column
+
+ There's currently no FIELDTYPE constant for this column, so the
+ return value is not a regular column object that could also be
+ returned from e.g. the Column() method. Only the name attribute
+ of the return value is meaningful at the moment.
+ """
+ return PostGISColumn(self.geometry_column, None, None)
+
+ def ShapeType(self):
+ """Return the type of the shapes in the shapestore."""
+ return self.shape_type
+
+ def RawShapeFormat(self):
+ """Return the raw data format of the shape data.
+
+ For the PostGISShapeStore this is RAW_WKT.
+ """
+ return RAW_WKT
+
+ def NumShapes(self):
+ # The number of shapes is the same as the number of rows,
+ # assuming that the geometry can't be NULL.
+ return self.NumRows()
+
+ def BoundingBox(self):
+ """Return the bounding box of all shapes in the postgis table"""
+ minx = miny = maxx = maxy = None
+ x=[]
+ y=[]
+ cursor = self.db.cursor()
+ try:
+ # Using the extent function is postgis specific. An OGC
+ # Simple Features compliant solution would be to use a query
+ # like "SELECT AsText(Envelope(the_geom)) FROM mytable;" and
+ # calculate the bounding box by hand from that
+ cursor.execute("SELECT extent(%s) FROM %s;"
+ % (self.quoted_geo_col, self.quoted_tablename))
+ result = cursor.fetchone()
+ if result[0]:
+ (minx, miny), (maxx, maxy) \
+ = wellknowntext.parse_wkt_thuban(result[0])[0]
+ return (minx, miny, maxx, maxy)
+ finally:
+ cursor.close()
+
+ def Shape(self, shapeid):
+ cursor = self.db.cursor()
+ cursor.execute("SELECT AsText(%s) FROM %s WHERE %s=%d"
+ % (self.quoted_geo_col, self.quoted_tablename,
+ self.quoted_id_column, shapeid))
+ wkt = cursor.fetchone()[0]
+ cursor.close()
+ return PostGISShape(shapeid, wkt)
+
+ def AllShapes(self):
+ cursor = self.db.cursor()
+ cursor.execute("SELECT %s, AsText(%s) FROM %s ORDER BY %s"
+ % (self.quoted_id_column, self.quoted_geo_col,
+ self.quoted_tablename, self.quoted_id_column))
+ while 1:
+ result = cursor.fetchone()
+ if result is None:
+ return
+ yield PostGISShape(result[0], result[1])
+
+
+ def ShapesInRegion(self, bbox):
+ """Generate all shapes overlapping the region given by bbox."""
+ # IMPORTANT:This will work for PostGIS < 0.8
+ left, bottom, right, top = bbox
+ geom = (("POLYGON((" + ", ".join(["%f %f"] * 5) + "))")
+ % (left, bottom, left, top, right, top, right, bottom,
+ left, bottom))
+ cursor = self.db.cursor()
+ cursor.execute("SELECT %(gid)s, AsText(%(geom)s) FROM %(table)s"
+ " WHERE %(geom)s && GeometryFromText('%(box)s', %(srid)d)"
+ " ORDER BY %(gid)s"
+ % {"table": self.quoted_tablename,
+ "geom": self.quoted_geo_col,
+ "gid": self.quoted_id_column,
+ "box": geom,
+ "srid": self.srid})
+ while 1:
+ result = cursor.fetchone()
+ if result is None:
+ return
+ yield PostGISShape(result[0], result[1])
Added: packages/thuban/branches/upstream/current/Thuban/Model/proj.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/proj.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/proj.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,218 @@
+# Copyright (c) 2001, 2003, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+__version__ = "$Revision: 2708 $"
+
+from types import StringTypes
+import locale
+
+from Thuban import _
+from Thuban.Lib.connector import Publisher
+
+import Projection
+BaseProjection = Projection.Projection
+del Projection
+
+from messages import PROJECTION_ADDED, PROJECTION_REPLACED, PROJECTION_REMOVED
+
+PROJ_UNITS_METERS = 1
+PROJ_UNITS_DEGREES = 2
+
+def _do_we_have_to_work_around_broken_proj():
+ """ If we have a problematic locale, check if proj results are good. """
+ if locale.localeconv()['decimal_point'] != '.':
+ params = ["proj=latlong", "to_meter=0.01745", "ellps=clrk66"]
+ proj = BaseProjection(params)
+ result1 = proj.Forward(1,1)
+
+ savedlocale = locale.getlocale(locale.LC_NUMERIC)
+ locale.setlocale(locale.LC_NUMERIC, "C")
+
+ proj = BaseProjection(params)
+ result2 = proj.Forward(1,1)
+
+ try:
+ locale.setlocale(locale.LC_NUMERIC, savedlocale)
+ except:
+ # python under some circumstances (observed 2.3.5-2 Debian Sarge)
+ # does not accept savedlocale directly
+ # deviating from the documentation
+ locale.setlocale(locale.LC_NUMERIC, savedlocale[0])
+ if result1 != result2:
+ return True
+ return False
+
+class Projection(BaseProjection):
+ """A proj4 projection object that remembers the parameters.
+
+ The proj library is not robust against decimal_point != '.' locales.
+ Since python 2.4 calls C extensions with the set locale, it can create
+ a problem. It seems that calling
+ self.assuregoodlocale()
+ self.assureinitlocale()
+ before BaseProjection.__init__() is enough to work around this.
+
+ We assuming that the locale stays the same after a projection
+ has been initialised
+ and thus we can return to it in self.assureinitlocale().
+ """
+
+ def __init__(self, params, name = None, epsg = None):
+ """Initialize the Projection
+
+ Parameters:
+
+ params -- a list of 'parameter=value' strings
+
+ name -- (optional) The name of the projection. If None or omitted
+ it defaults to 'Unknown' in the local language.
+
+ epsg -- (optional) The EPSG code as a string.
+ """
+ self.initlocale = locale.getlocale(locale.LC_NUMERIC)
+ self.work_around_broken_proj = _do_we_have_to_work_around_broken_proj()
+
+ self.assuregoodlocale()
+ BaseProjection.__init__(self, params)
+ self.assureinitlocale()
+
+ if name is None:
+ self.name = _("Unknown")
+ elif isinstance(name, StringTypes):
+ self.name = name
+
+ self.epsg = epsg
+ self.params = params
+
+ def assuregoodlocale(self):
+ if self.work_around_broken_proj:
+ locale.setlocale(locale.LC_NUMERIC, "C")
+
+ def assureinitlocale(self):
+ if self.work_around_broken_proj:
+ locale.setlocale(locale.LC_NUMERIC, self.initlocale)
+
+ def _transform_bbox(self, trafo, bbox):
+ # This is not really the correct way to determine the bbox of a
+ # projected bbox, but for now it works well enough
+ llx, lly, urx, ury = bbox
+ xs = []; ys = []
+ for x, y in ((llx, lly), (llx, ury), (urx, lly), (urx, ury)):
+ x, y = trafo(x, y)
+ xs.append(x); ys.append(y)
+ return min(xs), min(ys), max(xs), max(ys)
+
+ def ForwardBBox(self, bbox):
+ """Return the bounding box of the corners of the bounding box bbox
+ """
+ return self._transform_bbox(self.Forward, bbox)
+
+ def InverseBBox(self, bbox):
+ return self._transform_bbox(self.Inverse, bbox)
+
+ def GetName(self):
+ """Return the name of the projection."""
+ return self.name
+
+ def Label(self):
+ if self.epsg:
+ return "EPSG % 5s %s" % (self.epsg, self.name)
+ return self.name
+
+ def EPSGCode(self):
+ """Return the EPSG code as a string or None if there is none"""
+ return self.epsg
+
+ def GetParameter(self, param):
+ """Return the projection value for the given parameter.
+
+ If 'param' exists as a valid parameter return the associated
+ value as a string. If the parameter does not have a value (like
+ e.g. the 'south' parameter for utm) then the value is the
+ parameter name itself.
+
+ If the parameter doesn't exist return an empty string.
+ """
+
+ for pair in self.params:
+ if "=" in pair:
+ p, v = pair.split("=")
+ else:
+ p = v = pair
+ if p == param:
+ return v
+
+ return ""
+
+ def GetAllParameters(self):
+ """Return list of 'parameter=value' strings"""
+ return self.params
+
+ def GetProjectedUnits(self):
+ if self.GetParameter("proj") in [ 'latlong', 'longlat' ]:
+ return PROJ_UNITS_DEGREES
+ else:
+ return PROJ_UNITS_METERS
+
+ def __repr__(self):
+ return self.name + ": " + repr(self.params)
+
+
+class ProjFile(Publisher):
+
+ def __init__(self, filename):
+ """Intialize the ProjFile.
+
+ filename -- name of the file that this ProjFile represents.
+ """
+
+ self.__projs = []
+
+ self.SetFilename(filename)
+
+ def Add(self, proj):
+ """Add the projection to the end of the file."""
+ self.__projs.append(proj)
+ self.issue(PROJECTION_ADDED, proj)
+
+ def Remove(self, proj):
+ """Remove the object proj from the projection file.
+
+ Raises a ValueError is proj is not found.
+ """
+ self.__projs.remove(proj)
+ self.issue(PROJECTION_REMOVED, proj)
+
+ def Replace(self, oldproj, newproj):
+ """Replace the object 'oldproj' with 'newproj'.
+
+ Raises ValueError if oldproj is not in the file.
+ """
+ self.__projs[self.__projs.index(oldproj)] = newproj
+ self.issue(PROJECTION_REPLACED, oldproj, newproj)
+
+ def GetFilename(self):
+ """Return the filename where the ProjFile was read or will be
+ written to.
+ """
+
+ return self.__filename
+
+ def SetFilename(self, filename):
+ """Set the filename where the ProjFile will be written to."""
+ self.__filename = filename
+
+ def GetProjections(self):
+ """Return a list of the projections in the order they were read
+ from the file or will be written.
+
+ This is not a deep copy list, so any modifications made to the
+ Projection objects will be written to the file.
+ """
+
+ return self.__projs
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/range.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/range.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/range.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,146 @@
+# Copyright (C) 2002, 2003 by Intevation GmbH
+# Authors:
+# Thomas Koester <tkoester at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""
+Range class for Scientific Parameter
+"""
+
+__version__ = "$Revision: 1480 $"
+# $Source$
+# $Id: range.py 1480 2003-07-24 17:52:48Z bh $
+
+import re
+import types
+
+_inf = float('1e1000') # FIXME: hack for infinite
+
+class Range:
+
+ number_re = '(?P<%s>-?(\d*\.?\d*([eE][\-+]?\d+)?|oo))'
+ brace_re = '(?P<%s>[][])'
+ range_re = '^' + brace_re % 'left' + number_re % 'begin' + \
+ ';' + number_re % 'end' + brace_re % 'right' + '$'
+ parse_range = re.compile(range_re)
+
+ def __init__(self, range=None):
+ self._SetRange(range)
+
+ def _SetRange(self, range):
+ if isinstance(range, Range):
+ self._SetRange(range.GetRange())
+ elif range in [None, '']:
+ self._SetRange(']-oo;oo[')
+ elif type(range) == types.TupleType:
+ if (len(range) == 4 and range[0] in ['[', ']']
+ and range[3] in ['[', ']']):
+ self._left = range[0]
+ self._begin = self.float(range[1])
+ self._end = self.float(range[2])
+ self._right = range[3]
+ if (self._begin > self._end or
+ (self._begin == self._end and
+ (self._left != '[' or self._right != ']'))):
+ raise ValueError("illegal range: %s" % (range,))
+ else:
+ raise ValueError("can't parse range: %r" % (range,))
+ else:
+ self._range = range
+ match = self.parse_range.match(self._range)
+ if match:
+ self._SetRange((match.group('left'),
+ match.group('begin'),
+ match.group('end'),
+ match.group('right')))
+ else:
+ raise ValueError("can't parse range: %s" % (range,))
+
+ def GetRange(self):
+ """return internal representation of range
+
+ 4-tuple ('[' or ']', begin(float), end(float), '[' or ']')
+
+ """
+ return (self._left, self._begin, self._end, self._right)
+
+ def float(self, value):
+ """convert string or number to float"""
+ if value == 'oo':
+ return _inf
+ elif value == '-oo':
+ return -_inf
+ else:
+ return float(value)
+
+ def _float2string(self, value):
+ """convert float value to string
+
+ (minus) infinity will be converted to (-)oo,
+ scientific notation will be used if necessary.
+
+ """
+ if value == _inf:
+ return 'oo'
+ elif value == -_inf:
+ return '-oo'
+ else:
+ return "%g" % (value,)
+
+ def string(self, range):
+ """convert internal representation to string"""
+ left, begin, end, right = range
+ return "%s%s;%s%s" % (left, self._float2string(begin),
+ self._float2string(end), right)
+
+ def __contains__(self, value):
+ if self._left == ']':
+ contains = value > self._begin
+ else:
+ contains = value >= self._begin
+ if self._right == '[':
+ contains = contains and (value < self._end)
+ else:
+ contains = contains and (value <= self._end)
+ return contains
+
+ def __eq__(self, other):
+ return (self.GetRange() == other.GetRange())
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __str__(self):
+ return self.string(self.GetRange())
+
+
+def _test():
+ range1 = Range(']0;99]')
+ print 'range1 =', range1, range1.GetRange()
+ for i in [-0.1, 0, 0.1, 9.9, 99, 99.9]:
+ print '%4.1f in range1 =' % i, i in range1
+ range2 = Range(']-oo;10[')
+ print 'range2 =', range2, range2.GetRange()
+ for i in [-0.1, 0, 0.1, 9.9, 10, 10.1]:
+ print '%4.1f not in range2 =' % i, i not in range2
+ range3 = Range(']1e-1;1E2]')
+ print 'range3 =', range3, range3.GetRange()
+ for i in [0, 0.1, 0.11, 10, 100, 101]:
+ print '%4.1f not in range3 =' % i, i not in range3
+ print 'range3 != range2 =', range3 != range2
+ print 'range3 != Range("]1e-1;1E2]") =', range3 != Range("]1e-1;1E2]")
+
+ range4 = Range('')
+ print 'range4 =', range4, range4.GetRange()
+
+ range5 = Range(']0;99E+00]')
+ print 'range5 =', range5, range5.GetRange()
+ range6 = Range(']0;99E+01]')
+ print 'range6 =', range6, range6.GetRange()
+ range7 = Range(']0;99E-01]')
+ print 'range7 =', range7, range7.GetRange()
+
+if __name__ == "__main__":
+ _test()
Added: packages/thuban/branches/upstream/current/Thuban/Model/resource.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/resource.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/resource.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,235 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Handle resources loaded from files such as projections"""
+
+__version__ = "$Revision: 1964 $"
+# $Source$
+# $Id: resource.py 1964 2003-11-19 19:48:47Z bh $
+
+
+import os
+import os.path
+import weakref
+import traceback
+
+import Thuban
+from Thuban import _
+
+from Thuban.Lib.fileutil import get_application_dir
+
+from Thuban.Model.xmlreader import XMLReader
+from Thuban.Model.xmlwriter import XMLWriter
+from Thuban.Model.proj import Projection, ProjFile
+from xml.sax import SAXParseException
+
+projdir = \
+ os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Projections")
+
+
+PROJ_EXT = ".proj"
+
+# Determine the status of GDAL support. If GDAL is supported
+# gdal_support_status will be set to the empty string, otherwise to a
+# string with information why it isn't supported
+#
+# GDAL is supported if we can import both the thuban specific gdalwarp
+# module and the GDAL python bindings.
+for _module in ("gdalwarp", "gdal"):
+ try:
+ __import__(_module)
+ except ImportError, val:
+ gdal_support_status = (_("No GDAL support because module '%s'"
+ " cannot be imported. Python exception: '%s'")
+ % (_module, str(val)))
+ break
+else:
+ gdal_support_status = ""
+
+def has_gdal_support():
+ return gdal_support_status == ""
+
+
+projfile_cache = weakref.WeakValueDictionary()
+
+def clear_proj_file_cache():
+ """Clear the cache of ProjFile objects maintained by read_proj_file.
+
+ This function is probably only useful for the test suite.
+ """
+ projfile_cache.clear()
+
+def read_proj_file(filename):
+ """Read a .proj file and return a ProjFile object and warnings
+
+ The return value is a tuple with the ProjFile object and a list of
+ strings with warnings messages that might have been generated by the
+ proj file parser.
+
+ The objects returned cached so that reading the same file
+ (identified by its absolute name) several times yields the same
+ ProjFile object. The cache uses weak references so the objects will
+ be removed from the cache once the last reference an object in the
+ cache is removed.
+
+ Raises IOError if the file cannot be opened, OSError if the file
+ cannot be read and SAXParseException if the file is not valid XML.
+ """
+ filename = os.path.abspath(filename)
+ if filename in projfile_cache:
+ return projfile_cache[filename], []
+ else:
+ handler = ProjFileReader()
+ handler.read(filename)
+ proj_file = handler.GetProjFile()
+ projfile_cache[filename] = proj_file
+ return proj_file, handler.GetWarnings()
+
+def write_proj_file(pf):
+ """Write a single .proj file
+
+ Raises IOError if the file cannot be written.
+ """
+
+ saver = ProjFileSaver(pf)
+ saver.write(pf.GetFilename())
+
+#
+# Constants for the get_system_proj_file function
+#
+
+# The default projection file with a few predefined projections
+DEFAULT_PROJ_FILE = "defaults.proj"
+
+# The epsg projections.
+EPSG_PROJ_FILE = "epsg.proj"
+
+# Deprecated EPSG projections.
+EPSG_DEPRECATED_PROJ_FILE = "epsg-deprecated.proj"
+
+def get_system_proj_file(filename):
+ """Return the projections from the indicated file and a list with warnings
+
+ The filename argument should be the name of a file in the directory
+ with Thuban's default projection files (Resources/Projections/). If
+ possible callers should not use hardwired string literal for the
+ name to avoid unnecessary duplication. Instead they should use one
+ of the predefined constants, currently DEFAULT_PROJ_FILE,
+ EPSG_PROJ_FILE or EPSG_DEPRECATED_PROJ_FILE.
+
+ The return value is a tuple with the projections in a ProjFile
+ object and a list of strings with warning messages. The warnings
+ list is usually empty but may contain messages about ignored errors.
+
+ If the file could could not be opened return an empty projection
+ file object set to store data in the indicated default file.
+ """
+ fullname = os.path.join(projdir, filename)
+ try:
+ return read_proj_file(fullname)
+ except (OSError, IOError, SAXParseException), val:
+ msg = _('Could not read "%s": %s') % (fullname, str(val))
+ return ProjFile(fullname), [msg]
+
+def get_user_proj_file():
+ """Return the user's projections and a list with warnings
+
+ The projections read from the user's thuban projection file (usually
+ in ~/.thuban/user.proj). The return value is a tuple with the
+ projections in a ProjFile object and a list of strings with warning
+ messages. The warnings list is usually empty but may contain
+ messages about ignored errors.
+
+ If the file could could not be opened return an empty projection
+ file object set to store data in the default file.
+ """
+ usrdir = get_application_dir()
+ filename = os.path.join(usrdir, "user.proj")
+ try:
+ return read_proj_file(filename)
+ except (OSError, IOError, SAXParseException), val:
+ msg = _('Could not read "%s": %s') % (filename, str(val))
+ return ProjFile(filename), [msg]
+
+
+class ProjFileReader(XMLReader):
+
+ def __init__(self):
+ XMLReader.__init__(self)
+ self.projfile = ProjFile("")
+ self.warnings = []
+
+ XMLReader.AddDispatchers(self,
+ {'projection': ("start_projection", "end_projection"),
+ 'parameter': ("start_parameter", None)})
+
+ def read(self, file_or_filename):
+ XMLReader.read(self, file_or_filename)
+
+ self.projfile.SetFilename(XMLReader.GetFilename(self))
+
+ def start_projection(self, name, qname, attrs):
+ self.params = []
+ name = self.encode(attrs.get((None, 'name')))
+ if name is None:
+ name = _("Unknown")
+ self.name = name
+ self.epsg = self.encode(attrs.get((None, 'epsg')))
+
+ def end_projection(self, name, qname):
+ try:
+ proj = Projection(self.params, self.name, epsg = self.epsg)
+ except IOError, val:
+ self.warnings.append(_('Error in projection "%s": %s')
+ % (self.name, str(val)))
+ else:
+ self.projfile.Add(proj)
+
+ def start_parameter(self, name, qname, attrs):
+ s = attrs.get((None, 'value'))
+ s = str(s) # we can't handle unicode in proj
+ self.params.append(s)
+
+ def GetProjFile(self):
+ return self.projfile
+
+ def GetWarnings(self):
+ """Return the list of warning messages that may have been produced"""
+ return self.warnings
+
+
+class ProjFileSaver(XMLWriter):
+
+ def __init__(self, pf):
+ XMLWriter.__init__(self)
+ self.__pf = pf
+
+ def write(self, file_or_filename):
+ XMLWriter.write(self, file_or_filename)
+
+ self.write_header("projectionlist", "projfile.dtd")
+ self.write_projfile(self.__pf)
+ self.close()
+
+ def write_projfile(self, pf):
+
+ self.open_element("projectionlist")
+
+ for p in pf.GetProjections():
+ attrs = {"name": p.GetName()}
+ if p.EPSGCode():
+ attrs["epsg"] = p.EPSGCode()
+ self.open_element("projection", attrs)
+
+ for param in p.GetAllParameters():
+ self.write_element("parameter", {"value": param})
+
+ self.close_element("projection")
+
+ self.close_element("projectionlist")
+
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/save.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/save.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/save.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,405 @@
+# Copyright (c) 2001-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2004-2005)
+# Bernhard Herzog <bh at intevation.de> (2001-2004)
+# Jonathan Coles <jonathan at intevation.de> (2003)
+# Frank Koormann <frank at intevation.de> (2003)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Functions to save a session to a file
+"""
+
+__version__ = "$Revision: 2688 $"
+# $Source$
+# $Id: save.py 2688 2006-06-30 12:27:20Z frank $
+
+import os
+
+import Thuban.Lib.fileutil
+
+from Thuban.Model.layer import Layer, RasterLayer
+
+from Thuban.Model.classification import \
+ ClassGroupDefault, ClassGroupSingleton, ClassGroupRange, \
+ ClassGroupPattern, ClassGroupMap
+from Thuban.Model.transientdb import AutoTransientTable, TransientJoinedTable
+from Thuban.Model.table import DBFTable, FIELDTYPE_STRING
+from Thuban.Model.data import DerivedShapeStore, FileShapeStore, \
+ SHAPETYPE_POINT
+
+from Thuban.Model.xmlwriter import XMLWriter
+from postgisdb import PostGISConnection, PostGISShapeStore
+
+def relative_filename(dir, filename):
+ """Return a filename relative to dir for the absolute file name absname.
+
+ This is almost the same as the function in fileutil, except that dir
+ can be an empty string in which case filename will be returned
+ unchanged.
+ """
+ if dir:
+ return Thuban.Lib.fileutil.relative_filename(dir, filename)
+ else:
+ return filename
+
+
+def unify_filename(filename):
+ """Return a 'unified' version of filename
+
+ The .thuban files should be as platform independent as possible.
+ Since they must contain filenames the filenames have to unified. We
+ unify on unix-like filenames for now, which means we do nothing on a
+ posix system and simply replace backslashes with slashes on windows
+ """
+ if os.name == "posix":
+ return filename
+ elif os.name == "nt":
+ return "/".join(filename.split("\\"))
+ else:
+ raise RuntimeError("Unsupported platform for unify_filename: %s"
+ % os.name)
+
+def sort_data_stores(stores):
+ """Return a topologically sorted version of the sequence of data containers
+
+ The list is sorted so that data containers that depend on other data
+ containers have higher indexes than the containers they depend on.
+ """
+ if not stores:
+ return []
+ processed = {}
+ result = []
+ todo = stores[:]
+ while todo:
+ # It doesn't really matter which if the items of todo is
+ # processed next, but if we take the first one, the order is
+ # preserved to some degree which makes writing some of the test
+ # cases easier.
+ container = todo.pop(0)
+ if id(container) in processed:
+ continue
+ deps = [dep for dep in container.Dependencies()
+ if id(dep) not in processed]
+ if deps:
+ todo.append(container)
+ todo.extend(deps)
+ else:
+ result.append(container)
+ processed[id(container)] = 1
+ return result
+
+def bool2str(b):
+ if b: return "true"
+ else: return "false"
+
+class SessionSaver(XMLWriter):
+
+ """Class to serialize a session into an XML file.
+
+ Applications built on top of Thuban may derive from this class and
+ override or extend the methods to save additional information. This
+ additional information should take the form of additional attributes
+ or elements whose names are prefixed with a namespace. To define a
+ namespace derived classes should extend the write_session method to
+ pass the namespaces to the default implementation.
+ """
+
+
+ def __init__(self, session):
+ XMLWriter.__init__(self)
+ self.session = session
+ # Map object ids to the ids used in the thuban files
+ self.idmap = {}
+
+ def get_id(self, obj):
+ """Return the id used in the thuban file for the object obj"""
+ return self.idmap.get(id(obj))
+
+ def define_id(self, obj, value = None):
+ if value is None:
+ value = "D" + str(id(obj))
+ self.idmap[id(obj)] = value
+ return value
+
+ def has_id(self, obj):
+ return self.idmap.has_key(id(obj))
+
+ def prepare_filename(self, filename):
+ """Return the string to use when writing filename to the thuban file
+
+ The returned string is a unified version (only slashes as
+ directory separators, see unify_filename) of filename expressed
+ relative to the directory the .thuban file is written to.
+ """
+ return unify_filename(relative_filename(self.dir, filename))
+
+ def write(self, file_or_filename):
+ XMLWriter.write(self, file_or_filename)
+
+ self.write_header("session", "thuban-1.1.dtd")
+ self.write_session(self.session)
+ self.close()
+
+ def write_session(self, session, attrs = None, namespaces = ()):
+ """Write the session and its contents
+
+ By default, write a session element with the title attribute and
+ call write_map for each map contained in the session.
+
+ The optional argument attrs is for additional attributes and, if
+ given, should be a mapping from attribute names to attribute
+ values. The values should not be XML-escaped yet.
+
+ The optional argument namespaces, if given, should be a sequence
+ of (name, URI) pairs. The namespaces are written as namespace
+ attributes into the session element. This is mainly useful for
+ derived classes that need to store additional information in a
+ thuban session file.
+ """
+ if attrs is None:
+ attrs = {}
+ attrs["title"] = session.title
+ for name, uri in namespaces:
+ attrs["xmlns:" + name] = uri
+ # default name space
+ attrs["xmlns"] = \
+ "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ self.open_element("session", attrs)
+ self.write_db_connections(session)
+ self.write_data_containers(session)
+ for map in session.Maps():
+ self.write_map(map)
+ self.close_element("session")
+
+ def write_db_connections(self, session):
+ for conn in session.DBConnections():
+ if isinstance(conn, PostGISConnection):
+ self.write_element("dbconnection",
+ {"id": self.define_id(conn),
+ "dbtype": "postgis",
+ "host": conn.host,
+ "port": conn.port,
+ "user": conn.user,
+ "dbname": conn.dbname})
+ else:
+ raise ValueError("Can't handle db connection %r" % conn)
+
+ def write_data_containers(self, session):
+ containers = sort_data_stores(session.DataContainers())
+ for container in containers:
+ if isinstance(container, AutoTransientTable):
+ # AutoTransientTable instances are invisible in the
+ # thuban files. They're only used internally. To make
+ # sure that containers depending on AutoTransientTable
+ # instances refer to the right real containers we give
+ # the AutoTransientTable instances the same id as the
+ # source they depend on.
+ self.define_id(container,
+ self.get_id(container.Dependencies()[0]))
+ continue
+
+ idvalue = self.define_id(container)
+ if isinstance(container, FileShapeStore):
+ self.define_id(container.Table(), idvalue)
+ filename = self.prepare_filename(container.FileName())
+ self.write_element("fileshapesource",
+ {"id": idvalue, "filename": filename,
+ "filetype": container.FileType()})
+ elif isinstance(container, DerivedShapeStore):
+ shapesource, table = container.Dependencies()
+ self.write_element("derivedshapesource",
+ {"id": idvalue,
+ "shapesource": self.get_id(shapesource),
+ "table": self.get_id(table)})
+ elif isinstance(container, PostGISShapeStore):
+ conn = container.DBConnection()
+ self.write_element("dbshapesource",
+ {"id": idvalue,
+ "dbconn": self.get_id(conn),
+ "tablename": container.TableName(),
+ "id_column": container.IDColumn().name,
+ "geometry_column":
+ container.GeometryColumn().name,
+ })
+ elif isinstance(container, DBFTable):
+ filename = self.prepare_filename(container.FileName())
+ self.write_element("filetable",
+ {"id": idvalue,
+ "title": container.Title(),
+ "filename": filename,
+ "filetype": "DBF"})
+ elif isinstance(container, TransientJoinedTable):
+ left, right = container.Dependencies()
+ left_field = container.left_field
+ right_field = container.right_field
+ self.write_element("jointable",
+ {"id": idvalue,
+ "title": container.Title(),
+ "right": self.get_id(right),
+ "rightcolumn": right_field,
+ "left": self.get_id(left),
+ "leftcolumn": left_field,
+ "jointype": container.JoinType()})
+ else:
+ raise ValueError("Can't handle container %r" % container)
+
+
+ def write_map(self, map):
+ """Write the map and its contents.
+
+ By default, write a map element element with the title
+ attribute, call write_projection to write the projection
+ element, call write_layer for each layer contained in the map
+ and finally call write_label_layer to write the label layer.
+ """
+ self.open_element('map title="%s"' % self.encode(map.title))
+ self.write_projection(map.projection)
+ for layer in map.Layers():
+ self.write_layer(layer)
+ self.write_label_layer(map.LabelLayer())
+ self.close_element('map')
+
+ def write_projection(self, projection):
+ """Write the projection.
+ """
+ if projection and len(projection.params) > 0:
+ attrs = {"name": projection.GetName()}
+ epsg = projection.EPSGCode()
+ if epsg is not None:
+ attrs["epsg"] = epsg
+ self.open_element("projection", attrs)
+ for param in projection.params:
+ self.write_element('parameter value="%s"' %
+ self.encode(param))
+ self.close_element("projection")
+
+ def write_layer(self, layer, attrs = None):
+ """Write the layer.
+
+ The optional argument attrs is for additional attributes and, if
+ given, should be a mapping from attribute names to attribute
+ values. The values should not be XML-escaped yet.
+ """
+
+ if attrs is None:
+ attrs = {}
+
+ attrs["title"] = layer.title
+ attrs["visible"] = bool2str(layer.Visible())
+
+ if isinstance(layer, Layer):
+ attrs["shapestore"] = self.get_id(layer.ShapeStore())
+ self.open_element("layer", attrs)
+ self.write_projection(layer.GetProjection())
+ self.write_classification(layer)
+ self.close_element("layer")
+ elif isinstance(layer, RasterLayer):
+ attrs["filename"] = self.prepare_filename(layer.filename)
+
+ masknames = ["none", "bit", "alpha"]
+
+ if layer.MaskType() != layer.MASK_BIT:
+ attrs["masktype"] = masknames[layer.MaskType()]
+
+ if layer.Opacity() != 1:
+ attrs["opacity"] = str(layer.Opacity())
+
+ self.open_element("rasterlayer", attrs)
+ self.write_projection(layer.GetProjection())
+ self.close_element("rasterlayer")
+
+ def write_classification(self, layer, attrs = None):
+ """Write Classification information."""
+
+ if attrs is None:
+ attrs = {}
+
+ lc = layer.GetClassification()
+
+ field = layer.GetClassificationColumn()
+
+ if field is not None:
+ attrs["field"] = field
+ attrs["field_type"] = str(layer.GetFieldType(field))
+
+ self.open_element("classification", attrs)
+
+ for g in lc:
+ if isinstance(g, ClassGroupDefault):
+ open_el = 'clnull label="%s"' % self.encode(g.GetLabel())
+ close_el = 'clnull'
+ elif isinstance(g, ClassGroupSingleton):
+ if layer.GetFieldType(field) == FIELDTYPE_STRING:
+ value = self.encode(g.GetValue())
+ else:
+ value = str(g.GetValue())
+ open_el = 'clpoint label="%s" value="%s"' \
+ % (self.encode(g.GetLabel()), value)
+ close_el = 'clpoint'
+ elif isinstance(g, ClassGroupRange):
+ open_el = 'clrange label="%s" range="%s"' \
+ % (self.encode(g.GetLabel()), str(g.GetRange()))
+ close_el = 'clrange'
+ elif isinstance(g, ClassGroupPattern):
+ open_el = 'clpattern label="%s" pattern="%s"' \
+ % (self.encode(g.GetLabel()), str(g.GetPattern()))
+ close_el = 'clpattern'
+
+ else:
+ assert False, _("Unsupported group type in classification")
+ continue
+
+ data = g.GetProperties()
+ dict = {'stroke' : data.GetLineColor().hex(),
+ 'stroke_width': str(data.GetLineWidth()),
+ 'fill' : data.GetFill().hex()}
+
+ # only for point layers write the size attribute
+ if layer.ShapeType() == SHAPETYPE_POINT:
+ dict['size'] = str(data.GetSize())
+
+ self.open_element(open_el)
+ self.write_element("cldata", dict)
+ self.close_element(close_el)
+
+ self.close_element("classification")
+
+ def write_label_layer(self, layer):
+ """Write the label layer.
+ """
+ labels = layer.Labels()
+ if labels:
+ self.open_element('labellayer')
+ for label in labels:
+ self.write_element(('label x="%g" y="%g" text="%s"'
+ ' halign="%s" valign="%s"')
+ % (label.x, label.y,
+ self.encode(label.text),
+ label.halign,
+ label.valign))
+ self.close_element('labellayer')
+
+
+
+def save_session(session, file, saver_class = None):
+ """Save the session session to a file.
+
+ The file argument may either be a filename or an open file object.
+
+ The optional argument saver_class is the class to use to serialize
+ the session. By default or if it's None, the saver class will be
+ SessionSaver.
+
+ If writing the session is successful call the session's
+ UnsetModified method
+ """
+ if saver_class is None:
+ saver_class = SessionSaver
+ saver = saver_class(session)
+ saver.write(file)
+
+ # after a successful save consider the session unmodified.
+ session.UnsetModified()
Added: packages/thuban/branches/upstream/current/Thuban/Model/scalebar.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/scalebar.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/scalebar.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,58 @@
+# Copyright (c) 2001, 2002 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 913 $"
+
+from Thuban import _
+
+def deriveInterval(width, scale):
+ """Calculate scalebar interval and unit which fits width for scale."""
+ try:
+ interval = width / scale
+ except ZeroDivisionError:
+ return -1, ''
+
+ if interval / 1000 > 1:
+ interval = long(interval / 1000)
+ unit = 'km'
+ else:
+ interval = long(interval)
+ unit = 'm'
+
+ return interval, unit
+
+def roundInterval(d):
+ """Round float."""
+ if d<.001:
+ interval = long(d*10000)/10000.0
+ return interval, "%.4f" % interval
+ if d<.01:
+ interval = long(d*1000)/1000.0
+ return interval, "%.3f" % interval
+ if d<.1:
+ interval = long(d*100)/100.0
+ return interval, "%.2f" % interval
+ if d<1:
+ interval = long(d*10)/10.0
+ return interval, "%.1f" % interval
+ if d<10:
+ return long(d), "%d" % d
+ if d<100:
+ interval = long(d/10) * 10
+ return interval, "%d" % interval
+ if d<1000:
+ interval = long(d/100) * 100
+ return interval, "%d" % interval
+ if d<10000:
+ interval = long(d/1000) * 1000
+ return interval, "%d" % interval
+ if d<100000:
+ interval = long(d/10000) * 10000
+ return interval, "%d" % interval
+
+ return -1, ''
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/session.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/session.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/session.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,452 @@
+# Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2102 $"
+
+import os
+from tempfile import mktemp
+import weakref
+
+from messages import MAPS_CHANGED, EXTENSIONS_CHANGED, FILENAME_CHANGED, \
+ MAP_LAYERS_CHANGED, MAP_PROJECTION_CHANGED, \
+ LAYER_CHANGED, LAYER_PROJECTION_CHANGED, LAYER_VISIBILITY_CHANGED,\
+ EXTENSION_CHANGED, EXTENSION_OBJECTS_CHANGED, CHANGED, \
+ TABLE_REMOVED, DBCONN_ADDED, DBCONN_REMOVED
+
+from Thuban import _
+
+from base import TitledObject, Modifiable
+from map import Map
+from data import ShapefileStore
+from table import DBFTable
+import postgisdb
+
+from transientdb import TransientDatabase, AutoTransientTable
+
+class AutoRemoveFile:
+
+ """Remove a file once all references go away."""
+
+ def __init__(self, filename, tempdir = None):
+ """Initialize the AutoRemoveFile
+
+ Parameters:
+ filename -- The name of the file to remove in __del__
+ tempdir -- Another object simple stored as an instance variable.
+
+ As the name suggests the tempdir parameter is intended for a
+ temporary directory the file might be located in. The intended
+ use is that it's an instance of AutoRemoveDir.
+ """
+ self.filename = filename
+ self.tempdir = tempdir
+
+ def __del__(self, remove = os.remove):
+ remove(self.filename)
+
+class AutoRemoveDir:
+
+ """Remove a directory once all references go away
+
+ The intended use of this class together with AutoRemoveFile is for
+ temporary directories and files containd therein. An AutoRemoveDir
+ should be instantiated for the directory and passed as the tempdir
+ parameter to every AutoRemoveFile instance created for files in the
+ directory. An AutoRemoveFile shold be instantiated for every file
+ created in the directory so that the directory is automatically
+ removed once the last file is removed.
+ """
+
+ def __init__(self, filename):
+ """Initialize the AutoRemoveDir
+
+ The parameter is the name of the directory.
+ """
+ self.filename = filename
+
+ def __del__(self, rmdir = os.rmdir):
+ rmdir(self.filename)
+
+
+# WeakKey dictionary mapping objects like the transient_db to
+# AutoRemoveDir or AutoRemoveFile instances to make sure that the
+# temporary files and the directory are deleted but not before the
+# objects that use them go away.
+auto_remover = weakref.WeakKeyDictionary()
+
+class Session(TitledObject, Modifiable):
+
+ """A complete session.
+
+ A Session consists of arbitrary numbers of maps, tables and extensions
+
+ Session objects send the following events:
+
+ TITLE_CHANGED -- The title has changed. Parameters: the session.
+
+ FILENAME_CHANGED -- The filename has changed. No parameters.
+
+ MAPS_CHANGED -- Maps were added, removed.
+
+ EXTENSIONS_CHANGED -- Extensions were added, removed.
+
+ MAP_LAYERS_CHANGED -- Same as the map's event of the same name.
+ It's simply resent from the session to make
+ subscriptions easier.
+
+ CHANGED -- Generic changed event. Parameters: the session. The
+ event is always issued when any other changed event
+ is issused. This is useful for code that needs to be
+ notified whenever something in the session has
+ changed but it's too cumbersome or error-prone to
+ subscribe to all the individual events.
+ """
+
+ # message channels that have to be forwarded from maps contained in
+ # the session.
+ forwarded_channels = (
+ # generic channels
+ CHANGED,
+
+ # map specific channels
+ MAP_PROJECTION_CHANGED,
+ MAP_LAYERS_CHANGED,
+
+ # layer channels forwarded by the map
+ LAYER_PROJECTION_CHANGED,
+ LAYER_CHANGED,
+ LAYER_VISIBILITY_CHANGED,
+
+ # channels forwarded by an extension
+ EXTENSION_CHANGED,
+ EXTENSION_OBJECTS_CHANGED)
+
+ def __init__(self, title):
+ TitledObject.__init__(self, title)
+ Modifiable.__init__(self)
+ self.filename = None
+ self.maps = []
+ self.tables = []
+ self.shapestores = []
+ self.extensions = []
+ self.db_connections = []
+ self.temp_dir = None
+ self.transient_db = None
+
+ def changed(self, channel = None, *args):
+ """Like the inherited version but issue a CHANGED message as well.
+
+ The CHANGED message is only issued if channel given is a
+ different channel than CHANGED.
+ """
+ Modifiable.changed(self, channel, *args)
+ if channel != CHANGED:
+ self.issue(CHANGED, self)
+
+ def SetFilename(self, filename):
+ self.filename = filename
+ self.changed(FILENAME_CHANGED)
+
+ def Maps(self):
+ return self.maps
+
+ def HasMaps(self):
+ return len(self.maps) > 0
+
+ def AddMap(self, map):
+ self.maps.append(map)
+ for channel in self.forwarded_channels:
+ map.Subscribe(channel, self.forward, channel)
+ self.changed(MAPS_CHANGED)
+
+ def RemoveMap(self, map):
+ for channel in self.forwarded_channels:
+ map.Unsubscribe(channel, self.forward, channel)
+ self.maps.remove(map)
+ self.changed(MAPS_CHANGED)
+ map.Destroy()
+
+ def Extensions(self):
+ return self.extensions
+
+ def HasExtensions(self):
+ return len(self.extensions) > 0
+
+ def AddExtension(self, extension):
+ self.extensions.append(extension)
+ for channel in self.forwarded_channels:
+ extension.Subscribe(channel, self.forward, channel)
+ self.changed(EXTENSIONS_CHANGED)
+
+ def ShapeStores(self):
+ """Return a list of all ShapeStore objects open in the session"""
+ return [store() for store in self.shapestores]
+
+ def _add_shapestore(self, store):
+ """Internal: Add the shapestore to the list of shapestores"""
+ self.shapestores.append(weakref.ref(store,
+ self._clean_weak_store_refs))
+
+ def _clean_weak_store_refs(self, weakref):
+ """Internal: Remove the weakref from the shapestores list"""
+ self.shapestores = [store for store in self.shapestores
+ if store is not weakref]
+
+ def Tables(self):
+ """Return a list of all table objects open in the session
+
+ The list includes all tables that are indirectly opened through
+ shape stores and the tables that have been opened explicitly.
+ """
+ tables = self.tables[:]
+ ids = {}
+ for t in tables:
+ ids[id(t)] = 1
+ for store in self.ShapeStores():
+ t = store.Table()
+ if id(t) not in ids:
+ ids[id(t)] = 1
+ tables.append(t)
+ return tables
+
+ def UnreferencedTables(self):
+ """Return the tables that are not referenced by other data sources"""
+ known = {}
+ for table in self.tables:
+ known[id(table)] = 0
+ for table in self.tables + self.ShapeStores():
+ for dep in table.Dependencies():
+ known[id(dep)] = 1
+ return [table for table in self.tables if known[id(table)] == 0]
+
+ def AddTable(self, table):
+ """Add the table to the session
+
+ All tables associated with the session that are not implicitly
+ created by the OpenShapefile method (and maybe other Open*
+ methods in the future) have to be passed to this method to make
+ sure the session knows about it. The session keeps a reference
+ to the table. Only tables managed by the session in this way
+ should be used for layers contained in one of the session's
+ maps.
+
+ The table parameter may be any object implementing the table
+ interface. If it's not already one of the transient tables
+ instantiate an AutoTransientTable with it and use that instead
+ of the original table (note that the AutoTransientTable keeps a
+ reference to the original table).
+
+ Return the table object actually used by the session.
+ """
+ if not hasattr(table, "transient_table"):
+ transient_table = AutoTransientTable(self.TransientDB(), table)
+ else:
+ transient_table = table
+ self.tables.append(transient_table)
+ self.changed()
+ return transient_table
+
+ def RemoveTable(self, table):
+ """Remove the table from the session.
+
+ The table object must be a table object previously returned by
+ the AddTable method. If the table is not part of the session
+ raise a ValueError.
+
+ Issue a TABLE_REMOVED message after the table has been removed.
+ The message has the removed table as the single parameter.
+ """
+ tables = [t for t in self.tables if t is not table]
+ if len(tables) == len(self.tables):
+ raise ValueError
+ self.tables = tables
+ self.changed(TABLE_REMOVED, table)
+
+ def DataContainers(self):
+ """Return all data containers, i.e. shapestores and tables"""
+ return self.tables + self.ShapeStores()
+
+ def OpenTableFile(self, filename):
+ """Open the table file filename and return the table object.
+
+ The filename argument must be the name of a DBF file.
+ """
+ return self.AddTable(DBFTable(filename))
+
+ def temp_directory(self):
+ """
+ Return the name of the directory for session specific temporary files
+
+ Create the directory if it doesn't exist yet.
+ """
+ if self.temp_dir is None:
+ temp_dir = mktemp()
+ os.mkdir(temp_dir, 0700)
+ self.temp_dir = temp_dir
+ self.temp_dir_remover = AutoRemoveDir(self.temp_dir)
+ return self.temp_dir
+
+ def OpenShapefile(self, filename):
+ """Return a shapefile store object for the data in the given file"""
+ store = ShapefileStore(self, filename)
+ self._add_shapestore(store)
+ return store
+
+ def AddShapeStore(self, shapestore):
+ """Add the shapestore to the session.
+
+ The session only holds a weak reference to the shapestore, so it
+ will automatically be removed from the session when the last
+ reference goes away.
+ """
+ self._add_shapestore(shapestore)
+ return shapestore
+
+ def TransientDB(self):
+ if self.transient_db is None:
+ filename = os.path.join(self.temp_directory(), "transientdb")
+ self.transient_db = TransientDatabase(filename)
+ #print self.temp_dir_remover
+ auto_remover[self.transient_db] = AutoRemoveFile(filename,
+ self.temp_dir_remover)
+ return self.transient_db
+
+ def AddDBConnection(self, dbconn):
+ """Add the database connection dbconn to the session
+
+ The argument should be an instance of PostGISConnection.
+ """
+ self.db_connections.append(dbconn)
+ self.changed(DBCONN_ADDED)
+
+ def DBConnections(self):
+ """
+ Return a list of all database connections registered with the session
+ """
+ return self.db_connections
+
+ def HasDBConnections(self):
+ """Return whether the session has open database connections"""
+ return bool(self.db_connections)
+
+ def CanRemoveDBConnection(self, dbconn):
+ """Return whether the database connections dbconn can be removed
+
+ If can be removed if none of the shapestores or tables in the
+ session references it.
+ """
+ for store in self.ShapeStores():
+ if (isinstance(store, postgisdb.PostGISShapeStore)
+ and store.db is dbconn):
+ return 0
+ for table in self.Tables():
+ if (isinstance(table, postgisdb.PostGISTable)
+ and table.db is dbconn):
+ return 0
+ return 1
+
+ def RemoveDBConnection(self, dbconn):
+ """Remove the database connection from the session
+
+ The parameter must be a connection that was registered
+ previously by a AddDBConnection() call.
+ """
+ if self.CanRemoveDBConnection(dbconn):
+ remaining = [c for c in self.db_connections if c is not dbconn]
+ if len(remaining) < len(self.db_connections):
+ self.db_connections = remaining
+ self.changed(DBCONN_REMOVED)
+ else:
+ raise ValueError("DBConection %r is not registered"
+ " with session %r" % (dbconn, self))
+ else:
+ raise ValueError("DBConnection %r is still in use" % (dbconn,))
+
+ def OpenDBShapeStore(self, db, tablename, id_column = None,
+ geometry_column = None):
+ """Create and return a shapstore for a table in the database
+
+ The db parameter must be a database connection previously passed
+ to AddDBConnection().
+ """
+ store = postgisdb.PostGISShapeStore(db, tablename,
+ id_column = id_column,
+ geometry_column = geometry_column)
+ self._add_shapestore(store)
+ return store
+
+ def Destroy(self):
+ for map in self.maps:
+ map.Destroy()
+ self.maps = []
+ self.tables = []
+ Modifiable.Destroy(self)
+
+ # Close the transient DB explicitly so that it removes any
+ # journal files from the temporary directory
+ if self.transient_db is not None:
+ self.transient_db.close()
+
+ def forward(self, *args):
+ """Reissue events.
+
+ If the channel the event is forwarded to is a changed-channel
+ that is not the CHANGED channel issue CHANGED as well. An
+ channel is considered to be a changed-channel if it's name ends
+ with 'CHANGED'.
+ """
+ if len(args) > 1:
+ args = (args[-1],) + args[:-1]
+ apply(self.issue, args)
+ channel = args[0]
+ # It's a bit of a kludge to rely on the channel name for this.
+ if channel.endswith("CHANGED") and channel != CHANGED:
+ self.issue(CHANGED, self)
+
+ def WasModified(self):
+ """Return true if the session or one of the maps was modified"""
+ if self.modified:
+ return 1
+ else:
+ for map in self.maps:
+ if map.WasModified():
+ return 1
+ return 0
+
+ def UnsetModified(self):
+ """Unset the modified flag of the session and the maps"""
+ Modifiable.UnsetModified(self)
+ for map in self.maps:
+ map.UnsetModified()
+
+ def TreeInfo(self):
+ items = []
+ if self.filename is None:
+ items.append(_("Filename:"))
+ else:
+ items.append(_("Filename: %s") % self.filename)
+
+ if self.WasModified():
+ items.append(_("Modified"))
+ else:
+ items.append(_("Unmodified"))
+
+ items.extend(self.maps)
+ items.extend(self.extensions)
+
+ return (_("Session: %s") % self.title, items)
+
+
+def create_empty_session():
+ """Return an empty session useful as a starting point"""
+ import os
+ session = Session(_('unnamed session'))
+ session.SetFilename(None)
+ session.AddMap(Map(_('unnamed map')))
+ session.UnsetModified()
+ return session
Added: packages/thuban/branches/upstream/current/Thuban/Model/table.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/table.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/table.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,524 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jan-Oliver Wagner <jan at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes for handling tables of data.
+"""
+
+__version__ = "$Revision: 1961 $"
+
+import os
+import inspect
+import warnings
+
+from base import TitledObject
+
+import dbflib
+
+# the field types supported by a Table instance.
+FIELDTYPE_INT = "int"
+FIELDTYPE_STRING = "string"
+FIELDTYPE_DOUBLE = "double"
+
+
+# map the dbflib constants for the field types to our constants
+dbflib_fieldtypes = {dbflib.FTString: FIELDTYPE_STRING,
+ dbflib.FTInteger: FIELDTYPE_INT,
+ dbflib.FTDouble: FIELDTYPE_DOUBLE}
+
+
+class DBFColumn:
+
+ """Description of a column in a DBFTable
+
+ Instances have the following public attributes:
+
+ name -- Name of the column
+ type -- Type of the column (one of FIELDTYPE_STRING, FIELDTYPE_INT or\
+ FIELDTYPE_DOUBLE)
+ index -- The index of the column
+ width -- the width of the data in the column
+ prec -- The precision of the data (only valid for type == FIELDTYPE_DOUBLE)
+ """
+
+ def __init__(self, name, type, width, prec, index):
+ self.name = name
+ self.type = type
+ self.width = width
+ self.prec = prec
+ self.index = index
+
+
+class DBFTable(TitledObject):
+
+ """
+ Table interface for the data in a DBF file
+ """
+
+ # Implementation strategy regarding writing to a DBF file:
+ #
+ # Most of the time Thuban only needs to read from a table and it is
+ # important that Thuban can work with read-only files. Therefore the
+ # DBF file is opened only for reading initially. Only when
+ # write_record is called we try to open the DBF file for writing as
+ # well. If that succeeds the read/write DBF file will be used for
+ # all IO afterwards.
+ #
+ # It's important to use the same DBF file object for both reading
+ # and writing to make sure that reading a records after writing
+ # returns the new values. With two separate objects this wouldn't
+ # work because a DBF file object buffers some data
+
+ def __init__(self, filename):
+ self.filename = os.path.abspath(filename)
+
+ # Omit the extension in the title as it's not really needed and
+ # it can be confusing because dbflib removes extensions and
+ # appends some variations of '.dbf' before it tries to open the
+ # file. So the title could be e.g. myshapefile.shp when the real
+ # filename is myshapefile.dbf
+ title = os.path.splitext(os.path.basename(self.filename))[0]
+ TitledObject.__init__(self, title)
+
+ self.dbf = dbflib.DBFFile(filename)
+
+ # If true, self.dbf is open for writing.
+ self._writable = 0
+
+ # Create the column information objects
+ self.columns = []
+ self.column_map = {}
+ for i in range(self.NumColumns()):
+ ftype, name, width, prec = self.dbf.field_info(i)
+ ftype = dbflib_fieldtypes[ftype]
+ index = len(self.columns)
+ col = DBFColumn(name, ftype, width, prec, index)
+ self.columns.append(col)
+ self.column_map[name] = col
+ self.column_map[index] = col
+
+ def NumRows(self):
+ """Return the number of rows in the table"""
+ return self.dbf.record_count()
+
+ def NumColumns(self):
+ """Return the number of columns in the table"""
+ return self.dbf.field_count()
+
+ def Columns(self):
+ """Return the table's colum definitions
+
+ The return value is a sequence of DBFColumn instances, one for
+ each column.
+ """
+ return self.columns
+
+ def Column(self, col):
+ """Return information about the column given by its name or index
+
+ The returned object is an instance of DBFColumn
+ """
+ return self.column_map[col]
+
+ def HasColumn(self, col):
+ """Return whether the table has a column with the given name or index
+ """
+ return self.column_map.has_key(col)
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id
+
+ Since for DBFTables the row id is the row number, return the
+ value unchanged.
+ """
+ return gid
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal
+
+ Since for DBFTables the row id is the row number, return the
+ value unchanged.
+ """
+ return num
+
+ def ReadRowAsDict(self, row, row_is_ordinal = 0):
+ """Return the entire row as a dictionary with column names as keys
+
+ The row_is_ordinal is ignored for DBF tables because the row id
+ is always the row number.
+ """
+ return self.dbf.read_record(row)
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ """Return the value of the specified row and column
+
+ The col parameter may be the index of the column or its name.
+
+ The row_is_ordinal is ignored for DBF tables because the row id
+ is always the row number.
+ """
+ return self.dbf.read_attribute(row, self.column_map[col].index)
+
+ def ValueRange(self, col):
+ """Return the minimum and maximum values of the values in the column
+
+ The return value is a tuple (min, max) unless the table is empty
+ in which case the return value is None.
+ """
+ count = self.NumRows()
+
+ if count == 0:
+ return None
+
+ min = max = self.ReadValue(0, col)
+ for i in range(1, count):
+ value = self.ReadValue(i, col)
+ if value < min:
+ min = value
+ elif value > max:
+ max = value
+
+ return (min, max)
+
+ def UniqueValues(self, col):
+ """Return a sorted list of all unique values in the column col"""
+ dict = {}
+
+ for i in range(self.NumRows()):
+ value = self.ReadValue(i, col)
+ dict[value] = 0
+
+ values = dict.keys()
+ values.sort()
+ return values
+
+ def Dependencies(self):
+ """Return an empty sequence. The DBFTable doesn't depend on anything"""
+ return ()
+
+ # DBF specific interface parts.
+
+ def Width(self, col):
+ """Return column width"""
+ return self.column_map[col].width
+
+ def Destroy(self):
+ self.dbf.close()
+ self.dbf = None
+
+ def write_record(self, record, values):
+ """Write the values into the record
+
+ The values parameter may either be a dictionary or a sequence.
+
+ If it's a dictionary the keys must be the names of the fields
+ and their value must have a suitable type. Only the fields
+ actually contained in the dictionary are written. Fields for
+ which there's no item in the dict are not modified.
+
+ If it's a sequence, all fields must be present in the right
+ order.
+ """
+ if not self._writable:
+ new_dbf = dbflib.DBFFile(self.filename, "r+b")
+ self.dbf.close()
+ self.dbf = new_dbf
+ self._writable = 1
+ self.dbf.write_record(record, values)
+ self.dbf.commit()
+
+ def FileName(self):
+ """Return the filename the DBFTable was instantiated with"""
+ return self.filename
+
+
+class MemoryColumn:
+
+ def __init__(self, name, type, index):
+ self.name = name
+ self.type = type
+ self.index = index
+
+class MemoryTable(TitledObject):
+
+ """Very simple table implementation that operates on a list of tuples"""
+
+ def __init__(self, fields, data):
+ """Initialize the MemoryTable
+
+ Parameters:
+ fields -- List of (name, field_type) pairs
+ data -- List of tuples, one for each row of data
+ """
+ self.data = data
+ title = 'MemoryTable'
+ TitledObject.__init__(self, title)
+
+ # Create the column information objects
+ self.columns = []
+ self.column_map = {}
+ for name, ftype in fields:
+ index = len(self.columns)
+ col = MemoryColumn(name, ftype, index)
+ self.columns.append(col)
+ self.column_map[name] = col
+ self.column_map[index] = col
+
+ def NumColumns(self):
+ """Return the number of columns in the table"""
+ return len(self.columns)
+
+ def Column(self, col):
+ """Return information about the column given by its name or index
+
+ The returned object is an instance of MemoryColumn.
+ """
+ return self.column_map[col]
+
+ def Columns(self):
+ """Return the table's colum definitions
+
+ The return value is a sequence of MemoryColumn instances, one
+ for each column.
+ """
+ return self.columns
+
+ def HasColumn(self, col):
+ """Return whether the table has a column with the given name or index
+ """
+ return self.column_map.has_key(col)
+
+ def NumRows(self):
+ """Return the number of rows in the table"""
+ return len(self.data)
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id
+
+ Since for MemoryTables the row id is the row number, return the
+ value unchanged.
+ """
+ return gid
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal
+
+ Since for MemoryTables the row id is the row number, return the
+ value unchanged.
+ """
+ return num
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ """Return the value of the specified row and column
+
+ The col parameter may be the index of the column or its name.
+
+ The row_is_ordinal is ignored for DBF tables because the row id
+ is always the row number.
+ """
+ return self.data[row][self.column_map[col].index]
+
+ def ReadRowAsDict(self, index, row_is_ordinal = 0):
+ """Return the entire row as a dictionary with column names as keys
+
+ The row_is_ordinal is ignored for DBF tables because the row id
+ is always the row number.
+ """
+ return dict([(col.name, self.data[index][col.index])
+ for col in self.columns])
+
+ def ValueRange(self, col):
+ """Return the minimum and maximum values of the values in the column
+
+ The return value is a tuple (min, max) unless the table is empty
+ in which case the return value is None.
+ """
+
+ index = self.column_map[col].index
+ values = [row[index] for row in self.data]
+ if not values:
+ return None
+
+ return min(values), max(values)
+
+ def UniqueValues(self, col):
+ """Return a sorted list of all unique values in the column col
+
+ col can be either column index or name.
+ """
+ dict = {}
+
+ for i in range(self.NumRows()):
+ value = self.ReadValue(i, col)
+ dict[value] = 0
+
+ values = dict.keys()
+ values.sort()
+ return values
+
+ def Width(self, col):
+ """Return the maximum width of values in the column
+
+ The return value is the the maximum length of string
+ representation of the values in the column (represented by index
+ or name).
+ """
+ max = 0
+
+ type = self.column_map[col].type
+ index = self.column_map[col].index
+ values = [row[index] for row in self.data]
+ if not values:
+ return None
+
+ if type == FIELDTYPE_DOUBLE:
+ format = "%.12f"
+ elif type == FIELDTYPE_INT:
+ format = "%d"
+ else:
+ format = "%s"
+ for value in values:
+ l = len(format % value)
+ if l > max:
+ max = l
+
+ return max
+
+ def Dependencies(self):
+ """Return an empty sequence. The MemoryTable doesn't depend on anything
+ """
+ return ()
+
+ def write_record(self, record, values):
+ # TODO: Check for correct lenght and perhaps also
+ # for correct types in case values is a tuple. How to report problems?
+ # TODO: Allow values to be a dictionary and write the single
+ # fields that are specified.
+ self.data[record] = values
+
+
+
+def _find_dbf_column_names(names):
+ """Determine the column names to use in a DBF file
+
+ DBF files have a length limit of 10 characters on the column names
+ so when writing an arbitrary Thuban table to a DBF file we may have
+ we may have to rename some of the columns making sure that they're
+ unique in the DBF file too.
+
+ Names that are already short enough will stay the same. Longer names
+ will be truncated to 10 characters or if that isn't unique it will
+ be truncated more and filled up with digits.
+
+ The parameter names should be a list of the column names. The return
+ value will be a dictionary mapping the names in the input list to
+ the names to use in the DBF file.
+ """
+ # mapping from the original names in table to the names in the DBF
+ # file
+ name_map = {}
+
+ # First, we keep all names that are already short enough
+ for i in range(len(names) - 1, -1, -1):
+ if len(names[i]) <= 10:
+ name_map[names[i]] = names[i]
+ del names[i]
+
+ # dict used as a set of all names already used as DBF column names
+ used = name_map.copy()
+
+ # Go through all longer names. If the name truncated to 10
+ # characters is not used already, we use that. Otherwise we truncate
+ # it more and append numbers until we get an unused name
+ for name in names:
+ truncated = name[:10]
+ num = 0; numstr = ""
+ #print "truncated", truncated, num
+ while truncated in used and len(numstr) < 10:
+ num += 1
+ numstr = str(num)
+ truncated = name[:10 - len(numstr)] + numstr
+ #print "truncated", truncated, num
+ if len(numstr) >= 10:
+ # This case should never happen in practice as tables with
+ # 10^10 columns seem very unlikely :)
+ raise ValueError("Can't find unique dbf column name")
+
+ name_map[name] = truncated
+ used[truncated] = 1
+
+ return name_map
+
+def table_to_dbf(table, filename, rows = None):
+ """Create the dbf file filename from the table.
+
+ If rows is not None (the default) then it must be a list of row
+ indices to be saved to the file, otherwise all rows are saved.
+ """
+
+ dbf = dbflib.create(filename)
+
+ dbflib_fieldtypes = {FIELDTYPE_STRING: dbflib.FTString,
+ FIELDTYPE_INT: dbflib.FTInteger,
+ FIELDTYPE_DOUBLE: dbflib.FTDouble}
+
+
+ name_map = _find_dbf_column_names([col.name for col in table.Columns()])
+
+ # Initialise the header. Distinguish between DBFTable and others.
+ for col in table.Columns():
+ width = table.Width(col.name)
+ if col.type == FIELDTYPE_DOUBLE:
+ prec = getattr(col, "prec", 12)
+ else:
+ prec = 0
+ dbf.add_field(name_map[col.name], dbflib_fieldtypes[col.type],
+ width, prec)
+
+ if rows is None:
+ rows = range(table.NumRows())
+
+ recNum = 0
+ for i in rows:
+ record = {}
+ for key, value in table.ReadRowAsDict(i).items():
+ record[name_map[key]] = value
+ dbf.write_record(recNum, record)
+ recNum += 1
+ dbf.close()
+
+def table_to_csv(table, filename, rows = None):
+ """Export table to csv file.
+
+ If rows is not None (the default) then it must be a list of row
+ indices to be saved to the file, otherwise all rows are saved.
+ """
+
+ file = open(filename,"w")
+ columns = table.Columns()
+ if columns:
+ header = "#%s" % columns[0].name
+ for col in columns[1:]:
+ header = header + ",%s" % col.name
+ header = header + "\n"
+ file.write(header)
+
+ if rows is None:
+ rows = range(table.NumRows())
+
+ for i in rows:
+ record = table.ReadRowAsDict(i)
+ if len(record):
+ line = "%s" % record[columns[0].name]
+ for col in columns[1:]:
+ line = line + ",%s" % record[col.name]
+ line = line + "\n"
+ file.write(line)
+ file.close()
+
Added: packages/thuban/branches/upstream/current/Thuban/Model/transientdb.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/transientdb.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/transientdb.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,700 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Database for transient data
+
+This database is intended for data representations needed during the
+lifetime of a Thuban session but which is not permanent. Examples of
+this are for instance a join of two DBF files where the DBF files are
+the permanent representation of the data and the join only exists in the
+Thuban session and is reconstructed when the session is opened.
+"""
+
+__version__ = "$Revision: 2682 $"
+# $Source$
+# $Id: transientdb.py 2682 2006-05-15 20:11:15Z dpinte $
+
+# Pysqlite version 1. and 2. behaves quiet differently
+# Pysqlite uses a different paramstyle. The older version
+# support format and pyformat while pysqlite2 supports only qmark
+# and named.
+# The sqlite2 boolean variable is used to manage specific part of the code
+try:
+ # Using SQLITE 2.x
+ sqlite2 = True
+ from pysqlite2 import dbapi2 as sqlite
+except ImportError:
+ # Using SQLITE 1.x
+ sqlite2 = False
+ import sqlite
+
+
+from base import TitledObject
+
+import table
+
+sql_type_map = {
+ table.FIELDTYPE_INT: "INTEGER",
+ table.FIELDTYPE_STRING: "VARCHAR",
+ table.FIELDTYPE_DOUBLE: "FLOAT",
+ }
+
+type_converter_map = {
+ table.FIELDTYPE_INT: int,
+ table.FIELDTYPE_STRING: str,
+ table.FIELDTYPE_DOUBLE: float,
+ }
+
+class TransientDatabase:
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.conn = sqlite.connect(filename)
+ # Counters to produce unique table and column names
+ self.num_tables = 0
+ self.num_cols = 0
+ # Since there's only once process using the SQLite database, we
+ # might be able to get a tad more speed with default_synchronous
+ # OFF. So far I haven't seen any measurable speedup, though.
+ #self.execute("PRAGMA default_synchronous = OFF")
+
+ def __del__(self):
+ self.close()
+
+ def close(self):
+ if self.conn is not None:
+ self.conn.close()
+ self.conn = None
+
+ def new_table_name(self):
+ self.num_tables += 1
+ return "Table%03d" % self.num_tables
+
+ def new_column_name(self):
+ self.num_cols += 1
+ return "Col%03d" % self.num_cols
+
+ def execute(self, *args):
+ """execute the SQL statement in the database and return the result"""
+ cursor = self.conn.cursor()
+ cursor.execute(*args)
+ result = cursor.fetchone()
+ self.conn.commit()
+ return result
+
+ def cursor(self):
+ return self.conn.cursor()
+
+
+class ColumnReference:
+
+ def __init__(self, name, type, internal_name):
+ self.name = name
+ self.type = type
+ self.internal_name = internal_name
+
+
+class TransientTableBase:
+
+ """Base class for tables in the transient database"""
+
+ def __init__(self, transient_db):
+ """Initialize the table for use with the given transient db"""
+ self.db = transient_db
+ self.tablename = self.db.new_table_name()
+ self.indexed_columns = {}
+ self.read_record_cursor = None
+ self.read_record_last_row = None
+ self.read_record_last_result = None
+
+ def create(self, columns):
+ self.columns = columns
+ self.name_to_column = {}
+ self.orig_names = []
+ self.internal_to_orig = {}
+ self.orig_to_internal = {}
+ self.column_map = {}
+
+ # Create the column objects and fill various maps and lists
+ for index in range(len(self.columns)):
+ col = self.columns[index]
+ self.name_to_column[col.name] = col
+ self.orig_names.append(col.name)
+ self.internal_to_orig[col.internal_name] = col.name
+ self.orig_to_internal[col.name] = col.internal_name
+ self.column_map[col.name] = col
+ self.column_map[index] = col
+
+ # Build the CREATE TABLE statement and create the table in the
+ # database
+ table_types = ["id INTEGER PRIMARY KEY"]
+ for col in self.columns:
+ table_types.append("%s %s" % (col.internal_name,
+ sql_type_map[col.type]))
+ table_stmt = "CREATE TABLE %s (\n %s\n);" % (self.tablename,
+ ",\n ".join(table_types))
+ self.db.execute(table_stmt)
+
+ def transient_table(self):
+ """
+ Return a table whose underlying implementation is in the transient db
+ """
+ return self
+
+ def ensure_index(self, column):
+ """Ensure that there's an index on the given column"""
+ if not column in self.indexed_columns:
+ internal_name = self.orig_to_internal[column]
+ indexname = "Index_%s_%s" % (self.tablename, internal_name)
+ stmt = "CREATE INDEX %s ON %s (%s);" % (indexname, self.tablename,
+ internal_name)
+ self.db.execute(stmt)
+ self.indexed_columns[column] = 1
+
+ def NumColumns(self):
+ return len(self.columns)
+
+ def NumRows(self):
+ result = self.db.execute("SELECT count(*) FROM %s;" % self.tablename)
+ return int(result[0])
+
+ def Columns(self):
+ return self.columns
+
+ def Column(self, col):
+ return self.column_map[col]
+
+ def HasColumn(self, col):
+ """Return whether the table has a column with the given name or index
+ """
+ return self.column_map.has_key(col)
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id
+
+ At the moment the transient tables are only used for tables that
+ don't distinguish between row number and row id, so the value is
+ returned unchanged.
+ """
+ return gid
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal
+
+ At the moment the transient tables are only used for tables that
+ don't distinguish between row number and row id, so the value is
+ returned unchanged.
+ """
+ return num
+
+ def ReadRowAsDict(self, index, row_is_ordinal = 0):
+ """Return the entire row as a dictionary with column names as keys
+
+ The row_is_ordinal is ignored because at the moment the
+ transient tables are only used for DBF files where it doesn't
+ matter.
+ """
+ # Implementation Strategy: Executing a completely new select
+ # statement every time this method is called is too slow. The
+ # most important usage is to read the records more or less
+ # sequentially. This happens e.g. when drawing a layer with a
+ # classification where the shapes are drawn in order of the
+ # shape ids. Another pattern is that the same row is requested
+ # several times in a row. This happens in the table view, for
+ # instance.
+
+ # We can exploit this to make access faster by having one cursor
+ # open all the time and keeping the last row read around in case
+ # the same row is accessed again the next time and if the row
+ # index is larger than the row we have read last we simply fetch
+ # rows from the cursor until we've reached the requested row. If
+ # the requested row index is smaller then we start a new cursor.
+
+ # FIXME: So far this scheme seems to work well enough. Obvious
+ # improvements would be to start the cursor at exactly the
+ # requested row (should be efficient and easy to do now that the
+ # id is the primary key) and to perhaps to also start a new
+ # cursor if the requested index is much larger than the last row
+ # so that we don't read and discard lots of the rows.
+
+ # Check whether we have to start a new cursor
+ if self.read_record_cursor is None or index <self.read_record_last_row:
+ stmt = ("SELECT %s FROM %s;"
+ % (", ".join([c.internal_name for c in self.columns]),
+ self.tablename))
+ self.read_record_cursor = self.db.cursor()
+ self.read_record_cursor.execute(stmt)
+ self.read_record_last_row = -1
+ self.read_record_last_result = None
+
+ # Now we should have a cursor at a position less than or equal
+ # to the index so the following if statement will always set
+ # result to a suitable value
+ assert index >= self.read_record_last_row
+
+ if index == self.read_record_last_row:
+ result = self.read_record_last_result
+ else:
+ for i in range(index - self.read_record_last_row):
+ result = self.read_record_cursor.fetchone()
+ self.read_record_last_result = result
+ self.read_record_last_row = index
+ return dict(zip(self.orig_names, result))
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ """Return the value of the specified row and column
+
+ The col parameter may be the index of the column or its name.
+
+ The row_is_ordinal is ignored because at the moment the
+ transient tables are only used for DBF files where it doesn't
+ matter.
+ """
+ # Depending on the actual access patterns of the table data, it
+ # might be a bit faster in some circumstances to not implement
+ # this via ReadRowAsDict, but this simple implementation should
+ # be fast enough for most purposes.
+ return self.ReadRowAsDict(row)[self.column_map[col].name]
+
+ def ValueRange(self, col):
+ # Performance notes:
+ #
+ # In sqlite 2.8.6 the min and max aggregate functions can use an
+ # index but only when used as the only expression in the select
+ # statement (i.e. 'select min(col), max(col) from tbl;' will not
+ # use the index but 'select min(col) from tbl;' will) so we
+ # query the minimum and maximum separately.
+ #
+ # With the separate statements we can take advantage of an index
+ # if it exists. If the index doesn't exist, creating it first
+ # and then using it in the query is slower than the queries
+ # without an index. Creating the index is only an advantage if
+ # the queries are performed multiple times. With the current use
+ # patterns where ValueRange is only used occasionally by the
+ # classification generation dialog creating the index only for
+ # this usage is not really worth it, so we don't.
+ col = self.column_map[col]
+ iname = col.internal_name
+ min = self.db.execute("SELECT min(%s) FROM %s;"
+ % (iname, self.tablename))[0]
+ max = self.db.execute("SELECT max(%s) FROM %s;"
+ % (iname, self.tablename))[0]
+ converter = type_converter_map[col.type]
+ return (converter(min), converter(max))
+
+ def UniqueValues(self, col):
+ # Performance notes:
+ #
+ # In sqlite 2.8.6 there doesn't seem to be a way to query the
+ # unique items that uses an index. I've tried
+ #
+ # SELECT col FROM tbl GROUP BY col;
+ #
+ # and
+ #
+ # SELECT DISTINCT col FROM tbl;
+ #
+ # and in both cases the index is not used. If the index isn't
+ # used it doesn't make sense to call self.ensure_index.
+ iname = self.column_map[col].internal_name
+ cursor = self.db.cursor()
+ cursor.execute("SELECT %s FROM %s GROUP BY %s;"
+ % (iname, self.tablename, iname))
+ result = []
+ while 1:
+ row = cursor.fetchone()
+ if row is None:
+ break
+ result.append(row[0])
+ return result
+
+ def Width(self, col):
+ """Return the maximum width of values in the column
+
+ The return value is the the maximum length of string
+ representation of the values in the column (represented by index
+ or name).
+ """
+ max = 0
+
+ type = self.column_map[col].type
+ iname = self.column_map[col].internal_name
+ cursor = self.db.cursor()
+ cursor.execute("SELECT %s FROM %s;" % (iname, self.tablename))
+ values = [ i[0] for i in cursor.fetchall()]
+ if not values:
+ return None
+
+ if type == table.FIELDTYPE_DOUBLE:
+ format = "%.12f"
+ elif type == table.FIELDTYPE_INT:
+ format = "%d"
+ else:
+ format = "%s"
+ for value in values:
+ if value is None: continue
+ l = len(format % value)
+ if l > max:
+ max = l
+
+ return max
+
+ def SimpleQuery(self, left, comparison, right):
+ """Return the indices of all rows that matching a condition.
+
+ Parameters:
+ left -- The column object for the left side of the comparison
+
+ comparison -- The comparison operator as a string. It must be
+ one of '==', '!=', '<', '<=', '>=', '>'
+
+ right -- The right hand side of the comparison. It must be
+ either a column object or a value, i.e. a string,
+ int or float.
+
+ The return value is a sorted list of the indices of the rows
+ where the condition is true.
+ """
+ if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
+ raise ValueError("Comparison operator %r not allowed" % comparison)
+
+ if hasattr(right, "internal_name"):
+ right_template = right.internal_name
+ params = ()
+ else:
+ if sqlite2:
+ right_template = "?"
+ else: right_template = "%s"
+ params = (right,)
+
+ query = "SELECT id FROM %s WHERE %s %s %s ORDER BY id;" \
+ % (self.tablename, left.internal_name, comparison,
+ right_template)
+
+ cursor = self.db.cursor()
+ cursor.execute(query, params)
+ result = []
+ while 1:
+ row = cursor.fetchone()
+ if row is None:
+ break
+ result.append(row[0])
+ return result
+
+ def Dependencies(self):
+ """Placeholder for a method in a derived class.
+
+ Return a sequence with the tables and other data objects that
+ self depends on.
+ """
+ raise NotImplementedError
+
+
+class TransientTable(TitledObject, TransientTableBase):
+
+ """A Table in a transient DB that starts as the copy of a Thuban Table."""
+
+ def __init__(self, transient_db, table):
+ """Create a new table in the given transient DB as a copy of table
+
+ The table argument can be any object implementing the Table
+ interface.
+ """
+ TransientTableBase.__init__(self, transient_db)
+ TitledObject.__init__(self, table.Title())
+ self.create(table)
+
+ def create(self, table):
+ columns = []
+ for col in table.Columns():
+ columns.append(ColumnReference(col.name, col.type,
+ self.db.new_column_name()))
+ TransientTableBase.create(self, columns)
+
+ # copy the input table to the transient db
+
+ # A key to insert to use for the formatting of the insert
+ # statement. The key must not be equal to any of the column
+ # names so we construct one by building a string of x's that is
+ # longer than any of the column names
+ id_key = max([len(col.name) for col in self.columns]) * "x"
+
+ if sqlite2:
+ insert_template = "INSERT INTO %s (id, %s) VALUES (%s, %s);" \
+ % (self.tablename,
+ ", ".join([col.internal_name
+ for col in self.columns]),
+ '?',
+ ", ".join(["?" for col in self.columns]))
+
+ else:
+ insert_template = "INSERT INTO %s (id, %s) VALUES (%%(%s)s, %s);" \
+ % (self.tablename,
+ ", ".join([col.internal_name
+ for col in self.columns]),
+ id_key,
+ ", ".join(["%%(%s)s" % col.name
+ for col in self.columns]))
+ cursor = self.db.cursor()
+ for i in range(table.NumRows()):
+ row = table.ReadRowAsDict(i)
+ row[id_key] = i
+ if sqlite2:
+ params = [i]
+ for col in self.columns:
+ params.append(row[col.name])
+ cursor.execute(insert_template, params)
+ else:
+ cursor.execute(insert_template, row)
+ self.db.conn.commit()
+
+
+
+class TransientJoinedTable(TitledObject, TransientTableBase):
+
+ """A Table in the transient DB that contains a join of two tables"""
+
+ def __init__(self, transient_db, left_table, left_field,
+ right_table, right_field = None, outer_join = False):
+ """Create a new table in the transient DB as a join of two tables.
+
+ Both input tables, left_table and right_table must have a
+ transient_table method that returns a table object for a table
+ in the transient database. The join is performed on the condition
+ that the value of the left_field column the the left table is
+ equal to the value of the right_field in the right_table.
+
+ The joined table contains all columns of the input tables,
+ however, the column names of the right table may be changed
+ slightly to make them unique in the joined table. This is
+ currently done by appending a sufficient number of underscores
+ ('_').
+ """
+ TransientTableBase.__init__(self, transient_db)
+ self.dependencies = (left_table, right_table)
+ self.left_table = left_table.transient_table()
+ self.left_field = left_field
+ self.right_table = right_table.transient_table()
+ if right_field:
+ self.right_field = right_field
+ else:
+ self.right_field = self.left_field
+ self.outer_join = outer_join
+
+ title = "Join of %(left)s and %(right)s" \
+ % {"left": self.left_table.Title(),
+ "right": self.right_table.Title()}
+ TitledObject.__init__(self, title)
+
+ self.create()
+
+ def create(self):
+ """Internal: Create the table with the joined data"""
+ self.tablename = self.db.new_table_name()
+
+ self.right_table.ensure_index(self.right_field)
+
+ # determine the internal column names to join on before
+ # coalescing the column information because if the external
+ # column names are the same they will be mapped to the same
+ # internal name afterwards.
+ internal_left_col = self.left_table.orig_to_internal[self.left_field]
+ internal_right_col =self.right_table.orig_to_internal[self.right_field]
+
+ # Coalesce the column information
+ visited = {}
+ columns = []
+ newcolumns = []
+ for table in (self.left_table, self.right_table):
+ for col in table.Columns():
+ colname = col.name
+ # We can't allow multiple columns with the same
+ # original name, so append '_' to this one until
+ # it is unique.
+ # FIXME: There should be a better solution.
+ while colname in visited:
+ colname = colname + '_'
+ columns.append((table.tablename, col))
+ newcol = ColumnReference(colname, col.type,
+ "Col%03d" % (len(newcolumns)+1))
+ newcolumns.append(newcol)
+ visited[colname] = 1
+ TransientTableBase.create(self, newcolumns)
+
+ # Copy the joined data to the table.
+ newinternal_names = [col.internal_name for col in self.columns]
+ internal_references = ["%s.%s" % (table, col.internal_name)
+ for table, col in columns]
+ if self.outer_join:
+ join_operator = 'LEFT OUTER JOIN'
+ else:
+ join_operator = 'JOIN'
+ stmt = ("INSERT INTO %s (id, %s) SELECT %s.id, %s FROM %s"
+ " %s %s ON %s.%s = %s.%s;"
+ % (self.tablename,
+ ", ".join(newinternal_names),
+ self.left_table.tablename,
+ ", ".join(internal_references),
+ self.left_table.tablename,
+ join_operator,
+ self.right_table.tablename,
+ self.left_table.tablename,
+ internal_left_col,
+ self.right_table.tablename,
+ internal_right_col))
+ self.db.execute(stmt)
+
+ def Dependencies(self):
+ """Return a tuple with the two tables the join depends on."""
+ return self.dependencies
+
+ def JoinType(self):
+ """Return the type of the join (either 'INNER' or 'LEFT OUTER')"""
+ if self.outer_join:
+ return "LEFT OUTER"
+ else:
+ return "INNER"
+
+
+class AutoTransientTable(TitledObject):
+
+ """Table that copies data to a transient table on demand.
+
+ The AutoTransientTable takes another table as input and copies data
+ to a table in a TransientDatabase instance on demand.
+ """
+
+ def __init__(self, transient_db, table):
+ TitledObject.__init__(self, table.Title())
+ self.transient_db = transient_db
+ self.table = table
+ self.t_table = None
+
+ def Columns(self):
+ return self.table.Columns()
+
+ def Column(self, col):
+ return self.table.Column(col)
+
+ def HasColumn(self, col):
+ """Return whether the table has a column with the given name or index
+ """
+ return self.table.HasColumn(col)
+
+ def NumRows(self):
+ return self.table.NumRows()
+
+ def NumColumns(self):
+ return self.table.NumColumns()
+
+ def RowIdToOrdinal(self, gid):
+ """Return the row ordinal given its id"""
+ if self.t_table is not None:
+ return self.t_table.RowIdToOrdinal(gid)
+ else:
+ return self.table.RowIdToOrdinal(gid)
+
+ def RowOrdinalToId(self, num):
+ """Return the rowid for given its ordinal"""
+ if self.t_table is not None:
+ return self.t_table.RowOrdinalToId(num)
+ else:
+ return self.table.RowOrdinalToId(num)
+
+ def ReadRowAsDict(self, record, row_is_ordinal = 0):
+ """Return the record no. record as a dict mapping field names to values
+ """
+ if self.t_table is not None:
+ return self.t_table.ReadRowAsDict(record,
+ row_is_ordinal = row_is_ordinal)
+ else:
+ return self.table.ReadRowAsDict(record,
+ row_is_ordinal = row_is_ordinal)
+
+ def ReadValue(self, row, col, row_is_ordinal = 0):
+ """Return the value of the specified row and column
+
+ The col parameter may be the index of the column or its name.
+ """
+ if self.t_table is not None:
+ return self.t_table.ReadValue(row, col,
+ row_is_ordinal = row_is_ordinal)
+ else:
+ return self.table.ReadValue(row, col,
+ row_is_ordinal = row_is_ordinal)
+
+ def copy_to_transient(self):
+ """Internal: Create a transient table and copy the data into it"""
+ self.t_table = TransientTable(self.transient_db, self)
+
+ def transient_table(self):
+ """
+ Return a table whose underlying implementation is in the transient db
+ """
+ if self.t_table is None:
+ self.copy_to_transient()
+ return self.t_table
+
+ def ValueRange(self, col):
+ # Performance of sqlite vs. DBF for this method:
+ #
+ # If the table has been copied to the sqlite database it's
+ # faster to use it even if there is no index on that column.
+ # Otherwise it's faster to simply loop through all rows in the
+ # DBF file. Copying the data to the sqlite database can take
+ # very long for large amounts of data
+ #
+ # Of course if the table is not a DBF file the issue could be
+ # different, although copying the data into sqlite first will
+ # likely always be slower than simply querying the non-sqlite
+ # table directly. Currently only DBFfiles and memory tables are
+ # used as the underlying non-sqlite table, though.
+ if self.t_table is not None:
+ return self.t_table.ValueRange(col)
+ else:
+ return self.table.ValueRange(col)
+
+ def UniqueValues(self, col):
+ # The performance trade-offs for this method are basically the
+ # same as for ValueRange except that currently there doesn't
+ # seem to be a way to take advantage of indexes in this case in
+ # sqlite. However, but it's still faster to query the transient
+ # table if it already exists.
+ if self.t_table is not None:
+ return self.t_table.UniqueValues(col)
+ else:
+ return self.table.UniqueValues(col)
+
+ def SimpleQuery(self, left, comparison, right):
+ if self.t_table is None:
+ self.copy_to_transient()
+ # Make sure to use the column object of the transient table. The
+ # left argument is always a column object so we can just ask the
+ # t_table for the right object.
+ if hasattr(right, "name"):
+ return self.t_table.SimpleQuery(self.t_table.Column(left.name),
+ comparison,
+ self.t_table.Column(right.name))
+ else:
+ return self.t_table.SimpleQuery(self.t_table.Column(left.name),
+ comparison, right)
+
+ def Dependencies(self):
+ """Return a tuple containing the original table"""
+ return (self.table,)
+
+ def Width(self, col):
+ return self.table.Width(col)
+
+ def write_record(self, row, values):
+ """Write the values to the given row.
+
+ This is a very experimental feature which doesn't work in all
+ cases, so you better know what you're doing when calling this
+ method.
+ """
+ self.table.write_record(row, values)
Added: packages/thuban/branches/upstream/current/Thuban/Model/wellknowntext.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/wellknowntext.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/wellknowntext.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,135 @@
+# Copyright (C) 2002, 2003 Intevation GmbH <intevation at intevation.de>
+# Author: Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file GPL coming with the software for details.
+
+"""Convert Well-Known Text format to python objects
+
+Main entry point is the convert_well_known_text function which takes a
+geometry in Well-Known Text format and returns a python object with the
+geometry.
+"""
+
+__version__ = "$Revision: 1605 $"
+# $Source$
+# $Id: wellknowntext.py 1605 2003-08-19 11:00:40Z bh $
+
+import re
+
+
+_open_parens = r"[ \t]*(\([ \t]*)*"
+_close_parens = r"[ \t]*(\)[ \t]*)+"
+rx_point_list = re.compile(_open_parens + r"(?P<coords>[^\)]+)"
+ + _close_parens + ",?")
+
+
+def parse_coordinate_lists(wkt):
+ """Return the coordinates in wkt as a list of lists of coordinate pairs.
+
+ The wkt parameter is the coordinate part of a geometry in well-known
+ text format.
+ """
+ geometry = []
+ while wkt:
+ match = rx_point_list.match(wkt)
+ if match:
+ poly = []
+ wktcoords = match.group("coords")
+ for pair in wktcoords.split(","):
+ # a pair may be a triple actually. For now we just
+ # ignore any third value
+ x, y = map(float, pair.split())[:2]
+ poly.append((x, y))
+ geometry.append(poly)
+ wkt = wkt[match.end(0):].strip()
+ else:
+ raise ValueError("Invalid well-known-text (WKT) syntax")
+ return geometry
+
+
+def parse_multipolygon(wkt):
+ """
+ Return the MULTIPOLYGON geometry wkt as a list of lists of float pairs
+ """
+ return parse_coordinate_lists(wkt)
+
+def parse_polygon(wkt):
+ """Return the POLYGON geometry in wkt as a list of float pairs"""
+ return parse_coordinate_lists(wkt)
+
+def parse_multilinestring(wkt):
+ """
+ Return the MULTILINESTRING geometry wkt as a list of lists of float pairs
+ """
+ return parse_coordinate_lists(wkt)
+
+def parse_linestring(wkt):
+ """Return the LINESTRING geometry in wkt as a list of float pairs"""
+ return parse_coordinate_lists(wkt)[0]
+
+def parse_point(wkt):
+ """Return the POINT geometry in wkt format as pair of floats"""
+ return parse_coordinate_lists(wkt)[0][0]
+
+
+# map geometry types to parser functions
+_function_map = [
+ ("MULTIPOLYGON", parse_multipolygon),
+ ("POLYGON", parse_polygon),
+ ("MULTILINESTRING", parse_multilinestring),
+ ("LINESTRING", parse_linestring),
+ ("POINT", parse_point),
+ ]
+
+def convert_well_known_text(wkt):
+ """Return the geometry given in well-known text format as python objects
+
+ The function accepts only 2D data and supports the POINT, POLYGON,
+ MULTIPOLYGON, LINESTRING and MULTILINESTRING geometries.
+
+ The structure of the return value depends on the geometry type. For
+ MULTIPOLYGON and MULTILINESTRING return a list of lists of
+ coordinate pairs. For POLYGON and LINESTRING return a list of
+ coordinate pairs. For POINT return a coordinate pair. All
+ coordinates are floats.
+
+ The string wkt may contain an SRID specification in addition to the
+ actual geometry. This SRID is ignored.
+ """
+ parts = wkt.split(";")
+ for part in parts:
+ part = part.strip()
+ if part.startswith("SRID"):
+ # ignore SRIDs
+ continue
+ else:
+ for geotype, function in _function_map:
+ if part.startswith(geotype):
+ return function(part[len(geotype):])
+ else:
+ raise ValueError("Unsupported WKT-part %s" % repr(part[:20]))
+ else:
+ # there were no recognized geometries in the WKT string
+ raise ValueError("No recognized geometry in WKT string")
+
+def parse_wkt_thuban(wkt):
+ """Like convert_well_known_text, but return lists of lists of pairs"""
+ parts = wkt.split(";")
+ for part in parts:
+ part = part.strip()
+ if part.startswith("SRID"):
+ # ignore SRIDs
+ continue
+ else:
+ # split on "(" to separate the geometry type from the
+ # coordinate values
+ components = part.split("(", 1)
+ if len(components) > 1:
+ return parse_coordinate_lists(components[1])
+ else:
+ raise ValueError("WKT part %r doesn't contain opening"
+ " parenthesis" % part)
+ else:
+ # there were no recognized geometries in the WKT string
+ raise ValueError("No recognized geometry in WKT string")
Added: packages/thuban/branches/upstream/current/Thuban/Model/xmlreader.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/xmlreader.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/xmlreader.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,134 @@
+# Copyright (C) 2003, 2005 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with GRASS for details.
+
+"""
+Parser for thuban session files.
+"""
+
+__version__ = "$Revision: 2642 $"
+
+import os
+import xml.sax
+import xml.sax.handler
+from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
+from Thuban import internal_from_unicode
+
+class XMLReader(xml.sax.handler.ContentHandler):
+
+ # Dictionary mapping element names (or (URI, element name) pairs for
+ # documents using namespaces) to method names. The methods should
+ # accept the same parameters as the startElement (or startElementNS)
+ # methods. The start_dispatcher is used by the default startElement
+ # and startElementNS methods to call a method for the open tag of an
+ # element.
+ start_dispatcher = {}
+
+ # end_dispatcher works just like start_dispatcher but it's used by
+ # endElement and endElementNS. The method whose names it maps to
+ # should accept the same parameters as endElement and endElementNS.
+ end_dispatcher = {}
+
+
+ def __init__(self):
+ self.chars = ''
+ self.__directory = ""
+ self.__dispatchers = {}
+
+ def read(self, file_or_filename):
+
+ if hasattr(file_or_filename, "read"):
+ # it's a file object
+ self.__directory = ""
+ self.__file = file_or_filename
+ else:
+ filename = file_or_filename
+ self.__directory = os.path.dirname(filename)
+ self.__file = open(filename)
+
+ parser = make_parser()
+ parser.setContentHandler(self)
+ parser.setErrorHandler(ErrorHandler())
+ parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+
+ #
+ # Well, this isn't pretty, but it appears that if you
+ # use Python 2.2 without the site-package _xmlplus then
+ # the following will fail, and without them it will work.
+ # However, if you do have the site-package and you don't
+ # call these functions, the reader raises an exception
+ #
+ # The reason we set these to 0 in the first place is
+ # because there is an unresolved issue with external
+ # entities causing an exception in the reader
+ #
+ try:
+ parser.setFeature(xml.sax.handler.feature_validation,0)
+ parser.setFeature(xml.sax.handler.feature_external_ges,0)
+ parser.setFeature(xml.sax.handler.feature_external_pes,0)
+ except SAXNotRecognizedException:
+ pass
+
+ parser.parse(self.__file)
+
+ self.close()
+
+ def close(self):
+ self.__file.close()
+
+ def GetFilename(self):
+ if hasattr(self.__file, "name"):
+ return self.__file.name
+
+ return ""
+
+ def GetDirectory(self):
+ return self.__directory
+
+
+ def AddDispatchers(self, dict):
+ """Add the function names that should be used to process XML tags.
+
+ dict -- a dictionary whose keys are XML tag strings and whose values
+ are pairs of strings such that the first string is
+ the name of the function that should be called when the
+ XML tag opens and the second string is the name of the
+ function that should be called when the XML tag closes.
+ If a pair element is None, no function is called.
+ """
+
+ self.__dispatchers.update(dict)
+
+ def startElementNS(self, name, qname, attrs):
+ """Call the method given for name in self.start_dispatcher
+ """
+ if name[0] is None:
+ method_name = self.__dispatchers.get(name[1])
+ else:
+ # Dispatch with namespace
+ method_name = self.__dispatchers.get(name)
+ if method_name is not None and method_name[0] is not None:
+ getattr(self, method_name[0])(name, qname, attrs)
+
+ def endElementNS(self, name, qname):
+ """Call the method given for name in self.end_dispatcher
+ """
+ if name[0] is None:
+ method_name = self.__dispatchers.get(name[1])
+ else:
+ # Dispatch with namespace
+ method_name = self.__dispatchers.get(name)
+ if method_name is not None and method_name[1] is not None:
+ getattr(self, method_name[1])(name, qname)
+
+ def encode(self, str):
+ """Return the unicode object str in Thuban's internal representation
+
+ If str is None, return None
+ """
+ if str is None:
+ return None
+ return internal_from_unicode(str)
Added: packages/thuban/branches/upstream/current/Thuban/Model/xmlwriter.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/Model/xmlwriter.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/Model/xmlwriter.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,132 @@
+# Copyright (c) 2003, 2005 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Functions to save an XML file
+"""
+
+__version__ = "$Revision: 2642 $"
+
+import os
+from types import UnicodeType
+
+from Thuban import unicode_from_internal
+
+#
+# one level of indention
+#
+TAB = " "
+
+def escape(data):
+ """Escape &, \", ', <, and > in a string of data.
+ """
+ data = data.replace("&", "&")
+ data = data.replace("<", "<")
+ data = data.replace(">", ">")
+ data = data.replace('"', """)
+ data = data.replace("'", "'")
+ return data
+
+class XMLWriter:
+ """Abstract XMLWriter.
+
+ Should be overridden to provide specific object saving functionality.
+ """
+
+ def __init__(self):
+ self.filename = None
+ pass
+
+ def write(self, file_or_filename):
+ """Write the session to a file.
+
+ The argument may be either a file object or a filename. If it's
+ a filename, the file will be opened for writing. Files of
+ shapefiles will be stored as filenames relative to the directory
+ the file is stored in (as given by os.path.dirname(filename)) if
+ they have a common parent directory other than the root
+ directory.
+
+ If the argument is a file object (which is determined by the
+ presence of a write method) all filenames will be absolute
+ filenames.
+ """
+
+ # keep track of how many levels of indentation to write
+ self.indent_level = 0
+ # track whether an element is currently open. see open_element().
+ self.element_open = 0
+
+ if hasattr(file_or_filename, "write"):
+ # it's a file object
+ self.file = file_or_filename
+ self.dir = ""
+ else:
+ self.filename = file_or_filename
+ self.dir = os.path.dirname(self.filename)
+ self.file = open(self.filename, 'w')
+
+ def close(self):
+ assert self.indent_level == 0
+ if self.filename is not None:
+ self.file.close()
+
+ def write_header(self, doctype, system):
+ """Write the XML header"""
+ self.file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+ self.file.write('<!DOCTYPE %s SYSTEM "%s">\n' % (doctype, system))
+
+ def open_element(self, element, attrs = {}):
+
+ #
+ # we note when an element is opened so that if two open_element()
+ # calls are made successively we can end the currently open
+ # tag and will later write a proper close tag. otherwise,
+ # if a close_element() call is made directly after an open_element()
+ # call we will close the tag with a />
+ #
+ if self.element_open == 1:
+ self.file.write(">\n")
+
+ self.element_open = 1
+
+ # Helper function to write an element open tag with attributes
+ self.file.write("%s<%s" % (TAB*self.indent_level, element))
+ self.__write_attribs(attrs)
+
+ self.indent_level += 1
+
+ def close_element(self, element):
+ self.indent_level -= 1
+ assert self.indent_level >= 0
+
+ # see open_element() for an explanation
+ if self.element_open == 1:
+ self.element_open = 0
+ self.file.write("/>\n")
+ else:
+ self.file.write("%s</%s>\n" % (TAB*self.indent_level, element))
+
+ def write_element(self, element, attrs = {}):
+ """write an element that won't need a closing tag"""
+ self.open_element(element, attrs)
+ self.close_element(element)
+
+ def __write_attribs(self, attrs):
+ for name, value in attrs.items():
+ self.file.write(' %s="%s"' % (self.encode(name),
+ self.encode(value)))
+
+ def encode(self, s):
+ """Return an XML-escaped and UTF-8 encoded copy of the string s.
+
+ The parameter must be a string in Thuban's internal string
+ representation or a unicode object.
+ """
+ if not isinstance(s, unicode):
+ s = unicode_from_internal(s)
+ return escape(s).encode("utf8")
Added: packages/thuban/branches/upstream/current/Thuban/UI/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,77 @@
+# Copyright (c) 2001, 2002, 2003, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+_locale = None
+def install_wx_translation():
+ """Install the wx translation function in Thuban.
+
+ For more information about translations in Thuban see the comment in
+ Thuban/__init__.py
+ """
+ global _locale
+ import Thuban
+ if not Thuban.translation_function_installed():
+ # Only import wx modules when we actually can install the
+ # function so that the test suite can inhibit this
+ import wx
+ wx.Locale_AddCatalogLookupPathPrefix(Thuban._message_dir)
+ _locale = wx.Locale(wx.LANGUAGE_DEFAULT)
+ _locale.AddCatalog("thuban")
+
+ # With a unicode build of wxPython, wxGetTranslation returns a
+ # unicode object, so we have a wrapper that handles the case of
+ # not using unicode as the internal string representation of
+ # Thuban: If wxGetTranslation returns unicode and the internal
+ # string representation of Thuban is not unicode, we convert the
+ # translated string to the internal representation. wxPython
+ # will convert such strings back to unicode if necessary,
+ # provided the internal encoding used is the one expected by
+ # wxPython, which is taken care of below.
+ def thuban_wx_translation(s):
+ t = wx.GetTranslation(s)
+ if isinstance(t, unicode) and Thuban._internal_encoding!="unicode":
+ t = t.encode(Thuban._internal_encoding, "replace")
+ return t
+
+ Thuban.install_translation_function(thuban_wx_translation)
+
+ # Reset the python locale. This makes sure that the LC_NUMERIC
+ # seen by the python interpreter and by C modules is "C" instead
+ # of the user's locale. Python code will still see the user's
+ # locale where it matters. Without this, drawing the map doesn't
+ # work for some reason
+ import locale
+ locale.setlocale(locale.LC_NUMERIC, "")
+
+ # determine the internal encoding to use.
+ # This is very tricky. It's probably not optimal yet.
+ encoding = None
+
+ # If we have a wxPython >= 2.5.4.1, we use the
+ # GetDefaultPyEncoding function to use exactly what wxPython
+ # also uses when converting between unicode and byte-strings ...
+ if hasattr(wx, "GetDefaultPyEncoding"):
+ # AFAICT from the code this will always be a usable string,
+ # although it could be "ascii".
+ internal_encoding = wx.GetDefaultPyEncoding()
+
+ # ... otherwise we use Python's getdefaultlocale. This is what
+ # GetDefaultPyEncoding also uses ...
+ if encoding is None:
+ encoding = locale.getdefaultlocale()[1]
+
+ # ... finally, if we haven't figured it out yet, use latin 1 for
+ # historical reasons. Maybe ascii would be better.
+ if encoding is None:
+ encoding = "latin1"
+
+ # set the encoding
+ Thuban.set_internal_encoding(encoding)
+
+
+install_wx_translation()
Added: packages/thuban/branches/upstream/current/Thuban/UI/about.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/about.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/about.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,177 @@
+# Copyright (c) 2001-2007 by Intevation GmbH
+# vim: set fileencoding=ISO-8859-15 :
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de>
+# Silke Reimer <silke at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""The About Box"""
+
+__version__ = "$Revision: 2736 $"
+# $Source$
+# $Id: about.py 2736 2007-03-13 22:21:51Z bernhard $
+
+import wx
+
+from Thuban import _, internal_from_unicode, get_internal_encoding
+from Thuban.version import versions
+from Thuban.Model.resource import gdal_support_status
+
+from Thuban.UI.extensionregistry import ext_registry
+
+class About(wx.Dialog):
+
+ def __init__(self, parent):
+ wx.Dialog.__init__(self, parent, -1, _("About Thuban"),
+ style = wx.DEFAULT_DIALOG_STYLE
+ | wx.SYSTEM_MENU
+ | wx.MINIMIZE_BOX
+ | wx.MAXIMIZE_BOX
+ | wx.RESIZE_BORDER,
+ size = (400, 250))
+
+ # Note: The source code is in ASCII, so we escape some
+ # characters to get byte strings in latin1.
+ maintainers = [ 'Bernhard Reiter (2006 - current)',
+ 'Bernhard Herzog (2001 - 2005)' ]
+ lead_developer = 'Bernhard Herzog (2001 - 2005)'
+ developers = [ 'Jonathan Coles (2003, 2005)',
+ 'Frank Koormann (2002 - )',
+ internal_from_unicode(u'Martin M\xfcller (2003)'),
+ 'Didrik Pinte (2006 - )',
+ 'Bernhard Reiter (2004 - )',
+ 'Jan-Oliver Wagner (2002 - 2005)' ]
+ translators = [ ( _('French'), 'Daniel Calvelo Aros' ),
+ ( _('German'),
+ internal_from_unicode(u'Bj\xf6rn Broscheit')),
+ ( _('Hungarian'), 'Norbert Solymosi'),
+ ( _('Italian'), 'Maurizio Napolitano'),
+ ( _('Portuguese (Brazilian)'), 'Eduardo Patto Kanegae'),
+ ( _('Russian'), 'Alex Shevlakov'),
+ ( _('Spanish'), 'Daniel Calvelo Aros') ]
+ other_contributors = [ 'Jonathan Byron (2004)',
+ 'Ole Rahn (2004)',
+ 'Silke Reimer (2003, 2004)',
+ 'Martin "Joey" Schulze (2004, 2005)' ]
+ dyn_modules = [ ('wxPython', versions['wxPython']),
+ ('Python', versions['python']),
+ ('PySQLite', versions['pysqlite']),
+ ('SQLite', versions['sqlite']),
+ ('GDAL', versions.get('gdal', _('- not available'))),
+ ('psycopg', versions.get('psycopg',
+ _('- not available')))]
+ direct_modules = [ \
+ ('GTK', versions.get('gtk', _('- not available'))),
+ ('proj', versions['proj']) ]
+
+ text = 'Thuban %s\n\n' % versions['thuban-long']
+
+ text += _('Currently using:\n')
+
+ for name, version in dyn_modules:
+ text+= '\t%s %s\n' % (name, version)
+ text += '\n'
+
+ text += _('\tInternal encoding: %s\n') % get_internal_encoding()
+ text += '\n'
+
+ if gdal_support_status:
+ text += gdal_support_status + "\n\n"
+
+ text += _('Compiled for:\n')
+
+ for name, version in direct_modules:
+ text+= '\t%s %s\n' % (name, version)
+ text += '\n'
+
+ text += _('Extensions:\n')
+ if ext_registry:
+ for ext in ext_registry:
+ text += '\t%s %s\n' % (ext.name, ext.version)
+ else:
+ text += _('\tNone registered.\n')
+ text += '\n'
+
+ text += _('Maintainers:\n')
+ for name in maintainers:
+ text += '\t%s\n' % name
+ text += '\n'
+
+ text += _('Lead Developer:\n')
+ text += '\t%s\n\n' % lead_developer
+
+ text += _('Developers:\n')
+ for name in developers:
+ text += '\t%s\n' % name
+ text += '\n'
+
+ text += _('Translators:\n')
+ for lang, name in translators:
+ text += '\t%s: %s\n' % (lang, name)
+ text += '\n'
+
+ text += _('Other Contributors:\n')
+ for name in other_contributors:
+ text += '\t%s\n' % name
+ text += '\n'
+
+ text += \
+ _("Questions and comments can be sent to the following addresses:\n"
+ "\tGeneral list (public):\n\t\t<thuban-list at intevation.de>\n"
+ "\tDevelopers list (public):\n\t\t<thuban-devel at intevation.de>\n"
+ "\tThuban team at Intevation:\n\t\t<thuban at intevation.de>\n"
+ )
+
+ text += '\n\n'
+
+ text += _("Details on the registered extensions:\n\n")
+
+ if ext_registry:
+ for ext in ext_registry:
+ text += '%s %s:\n' % (ext.name, ext.version)
+ text += _('Copyright %s\n') % ext.copyright
+ text += _('Authors:\n')
+ for author in ext.authors:
+ text+= '\t%s\n' % author
+ text += ext.desc
+ text += '\n'
+ text += 'Status: %s' % ext.status
+ text += '\n\n'
+ else:
+ text += _('\tNone registered.\n')
+
+ self.text = text
+
+ text_title = wx.StaticText(self, -1,
+ _("Thuban is a program for exploring geographic data.\n\n") +
+ "Copyright 2001-2007 Intevation GmbH.\n" +
+ _("Thuban is licensed under the GNU GPL"),
+ style=wx.ST_NO_AUTORESIZE|wx.ALIGN_CENTRE)
+
+ textBox = wx.TextCtrl(self, -1, text,
+ style=wx.TE_READONLY|wx.TE_MULTILINE|wx.TE_LINEWRAP)
+ w, h = (300, 150)
+ textBox.SetSizeHints(w, h)
+ textBox.SetSize((w, h))
+
+ button_close = wx.Button(self, wx.ID_CANCEL, _("Close"))
+ button_close.SetDefault()
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(text_title, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
+ sizer.Add(textBox, 1, wx.ALL|wx.EXPAND, 10)
+ sizer.Add(button_close, 0, wx.ALL|wx.ALIGN_RIGHT, 10)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+ sizer.SetSizeHints(self)
+ self.Layout()
+
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=wx.ID_CANCEL)
+
+ def OnCancel(self, event):
+ self.EndModal(wx.ID_CANCEL)
Added: packages/thuban/branches/upstream/current/Thuban/UI/altpathdialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/altpathdialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/altpathdialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,60 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""Dialogs for alternative paths (path recovery).
+
+ AltPathFileDialog: File dialog to specify alterative path.
+ AltPathConfirmDialog: Confirm or cancel alternative path suggestion.
+"""
+
+from Thuban import _
+
+import wx
+
+import os
+
+class AltPathFileDialog(wx.FileDialog):
+
+ def __init__(self, filename):
+ msg = _("Select an alternative data file for %s" % \
+ os.path.basename(filename))
+
+ wx.FileDialog.__init__(self, None,
+ msg,
+ os.path.dirname(filename),
+ os.path.basename(filename),
+ _("Shapefiles (*.shp)") + "|*.shp;*.SHP|" +
+ _("All Files (*.*)") + "|*.*",
+ wx.OPEN)
+
+ def RunDialog(self):
+ val = self.ShowModal()
+ self.Destroy()
+ if val == wx.ID_OK:
+ return self.GetPaths()[0]
+ else:
+ return None
+
+class AltPathConfirmDialog(wx.MessageDialog):
+
+ def __init__(self, filename):
+ self.filename = filename
+ msg = _("Found the following as an alternative for %s.\n%s\n\n Please confirm with Yes or select alternative with No." % (os.path.basename(filename), filename))
+
+ wx.MessageDialog.__init__(self, None, msg, _("Alternative Path"),
+ wx.YES_NO|wx.YES_DEFAULT|wx.ICON_INFORMATION)
+
+ def RunDialog(self):
+ val = self.ShowModal()
+ self.Destroy()
+ if val == wx.ID_YES:
+ return self.filename
+ else:
+ dlg = AltPathFileDialog(self.filename)
+ fname = dlg.RunDialog()
+ return fname
Added: packages/thuban/branches/upstream/current/Thuban/UI/application.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/application.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/application.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,383 @@
+# Copyright (C) 2001-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Thuban's application object.
+"""
+
+__version__ = "$Revision: 2700 $"
+
+import sys, os
+import os.path
+
+import traceback
+
+import wx
+
+from Thuban.Lib.connector import Publisher
+from Thuban.Lib.fileutil import get_application_dir
+
+from Thuban import _
+from Thuban.Model.session import create_empty_session
+from Thuban.Model.save import save_session
+from Thuban.Model.load import load_session, LoadCancelled
+from Thuban.Model.messages import MAPS_CHANGED
+from Thuban.Model.layer import RasterLayer
+import Thuban.Model.resource
+
+from extensionregistry import ext_registry
+
+import view
+import tree
+import mainwindow
+import dbdialog
+import altpathdialog
+import exceptiondialog
+
+from messages import SESSION_REPLACED
+
+
+class ThubanApplication(wx.App, Publisher):
+
+ """
+ Thuban's application class.
+
+ All wxWindows programs have to have an instance of an application
+ class derived from wxApp. In Thuban the application class holds
+ references to the main window and the session.
+ """
+
+ def OnInit(self):
+ sys.excepthook = self.ShowExceptionDialog
+
+ # Initialize instance variables before trying to create any
+ # windows. Creating windows can start an event loop if
+ # e.g. message boxes are popped up for some reason, and event
+ # handlers, especially EVT_UPDATE_UI may want to access things
+ # from the application.
+
+ # Defaults for the directories used in file dialogs
+ self.path={"data":".", "projection":".", "alt_path":""}
+
+ self.session = None
+ self.top = None
+ self.create_session()
+
+ # Create an optional splash screen and then the mainwindow
+ self.splash = self.splash_screen()
+ if self.splash is not None:
+ self.splash.Show()
+ self.read_startup_files()
+ self.init_extensions()
+ self.top = self.CreateMainWindow()
+ # The session was alredy created above and we need to get the
+ # map into the mainwindow. maps_changed does that.
+ self.maps_changed()
+ self.SetTopWindow(self.top)
+ if self.splash is None:
+ self.ShowMainWindow()
+
+ return True
+
+ def OnExit(self):
+ """Clean up code.
+
+ Extend this in derived classes if needed.
+ """
+ self.session.Destroy()
+ self.session = None
+ Publisher.Destroy(self)
+
+ def read_startup_files(self):
+ """Read the startup files."""
+ # for now the startup file is ~/.thuban/thubanstart.py
+ dir = get_application_dir()
+ if os.path.isdir(dir):
+ sys.path.append(dir)
+ try:
+ import thubanstart
+ except ImportError:
+ tb = sys.exc_info()[2]
+ try:
+ if tb.tb_next is not None:
+ # The ImportError exception was raised from
+ # inside the thubanstart module.
+ sys.stderr.write(_("Cannot import the thubanstart"
+ " module\n"))
+ traceback.print_exc(None, sys.stderr)
+ else:
+ # There's no thubanstart module.
+ sys.stderr.write(_("No thubanstart module available\n"))
+ finally:
+ # make sure we delete the traceback object,
+ # otherwise there's be circular references involving
+ # the current stack frame
+ del tb
+ except:
+ sys.stderr.write(_("Cannot import the thubanstart module\n"))
+ traceback.print_exc(None, sys.stderr)
+ else:
+ # There's no .thuban directory
+ sys.stderr.write(_("No ~/.thuban directory\n"))
+
+ def init_extensions(self):
+ """Call initialization callbacks for all registered extensions."""
+ for ext in ext_registry:
+ ext.init_ext()
+
+ def splash_screen(self):
+ """Create and return a splash screen.
+
+ This method is called by OnInit to determine whether the
+ application should have a splashscreen. If the application
+ should display a splash screen override this method in a derived
+ class and have it create and return the wxSplashScreen instance.
+ The implementation of this method in the derived class should
+ also arranged for ShowMainWindow to be called.
+
+ The default implementation simply returns None so that no splash
+ screen is shown and ShowMainWindow will be called automatically.
+ """
+ return None
+
+ def ShowMainWindow(self):
+ """Show the main window
+
+ Normally this method is automatically called by OnInit to show
+ the main window. However, if the splash_screen method has
+ returned a splashscreen it is expected that the derived class
+ also arranges for ShowMainWindow to be called at the appropriate
+ time.
+ """
+ self.top.Show(True)
+
+ def CreateMainWindow(self):
+ """Create and return the main window for the application.
+
+ Override this in subclasses to instantiate the Thuban mainwindow
+ with different parameters or to use a different class for the
+ main window.
+ """
+ msg = (_("This is the wxPython-based Graphical User Interface"
+ " for exploring geographic data"))
+ return mainwindow.MainWindow(None, -1, "Thuban", self, None,
+ initial_message = msg,
+ size = (600, 400))
+
+ def Session(self):
+ """Return the application's session object"""
+ return self.session
+
+ def SetSession(self, session):
+ """Make session the new session.
+
+ Issue SESSION_REPLACED after self.session has become the new
+ session. After the session has been assigned call
+ self.subscribe_session() with the new session and
+ self.unsubscribe_session with the old one.
+ """
+ oldsession = self.session
+ self.session = session
+ self.subscribe_session(self.session)
+ self.issue(SESSION_REPLACED)
+ self.maps_changed()
+ if oldsession is not None:
+ self.unsubscribe_session(oldsession)
+ oldsession.Destroy()
+
+ def SetPath(self, group, filename):
+ """Store the application's default path for file dialogs extracted
+ from a given filename.
+ """
+ self.path[group] = os.path.dirname( filename )
+
+ def Path(self, group):
+ """Return the application's default path for file dialogs."""
+ return self.path[group]
+
+ def subscribe_session(self, session):
+ """Subscribe to some of the sessions channels.
+
+ Extend this method in derived classes if you need additional
+ channels.
+ """
+ session.Subscribe(MAPS_CHANGED, self.maps_changed)
+
+ def unsubscribe_session(self, session):
+ """Unsubscribe from the sessions channels.
+
+ Extend this method in derived classes if you subscribed to
+ additional channels in subscribe_session().
+ """
+ session.Unsubscribe(MAPS_CHANGED, self.maps_changed)
+
+ def create_session(self):
+ """Create a default session.
+
+ Override this method in derived classes to instantiate the
+ session differently or to use a different session class. Don't
+ subscribe to channels here yet. Do that in the
+ subscribe_session() method.
+ """
+ self.SetSession(create_empty_session())
+
+ def OpenSession(self, filename, db_connection_callback = None,
+ shapefile_callback = None):
+ """Open the session in the file named filename"""
+ # Make sure we deal with an absolute pathname. Otherwise we can
+ # get problems when saving because the saving code expects an
+ # absolute directory name
+ filename = os.path.abspath(filename)
+ if db_connection_callback is None:
+ db_connection_callback = self.run_db_param_dialog
+ if shapefile_callback is None:
+ shapefile_callback = self.run_alt_path_dialog
+ try:
+ session = load_session(filename,
+ db_connection_callback=db_connection_callback,
+ shapefile_callback=shapefile_callback)
+ except LoadCancelled:
+ return
+ session.SetFilename(filename)
+ session.UnsetModified()
+ self.SetSession(session)
+
+ for map in session.Maps():
+ for layer in map.Layers():
+ if isinstance(layer, RasterLayer) \
+ and not Thuban.Model.resource.has_gdal_support():
+ msg = _("The current session contains Image layers,\n"
+ "but the GDAL library is not available to "
+ "draw them.")
+ dlg = wx.MessageDialog(None,
+ msg,
+ _("Library not available"),
+ wx.OK | wx.ICON_INFORMATION)
+ print msg
+ dlg.ShowModal()
+ dlg.Destroy()
+ break
+
+ def run_db_param_dialog(self, parameters, message):
+ """Implementation of the db_connection_callback for loading sessions"""
+ dlg = dbdialog.DBDialog(None, _("DB Connection Parameters"),
+ parameters, message)
+ return dlg.RunDialog()
+
+ # run_alt_path_dialog: Raise a dialog to ask for an alternative path
+ # if the shapefile couldn't be found.
+ # TODO:
+ # - Store a list of already used alternative paths and return these
+ # iteratively (using a generator)
+ # - How do we interact with the user to tell him we used a different
+ # shapefile (location), mode "check"? The current approach with the
+ # file dialog is not that comfortable.
+ #
+ def run_alt_path_dialog(self, filename, mode = None, second_try = 0):
+ """Implemetation of the shapefile_callback while loading sessions.
+
+ This implements two modes:
+ - search: Search for an alternative path. If available from a
+ list of alrady known paths, else interactivly by file dialog.
+ Currently the "second_try" is important since else the user might
+ be caught in a loop.
+ - check: Ask the user for confirmation, if a path from list has
+ been found successful.
+
+ Returns:
+ - fname: The full path to the (shape) file.
+ - from_list: Flags if the path was taken from list or entered
+ manually.
+ """
+
+ if mode == "search":
+ if self.Path('alt_path') == "" or second_try:
+ dlg = altpathdialog.AltPathFileDialog(filename)
+ fname = dlg.RunDialog()
+ if fname is not None:
+ self.SetPath('alt_path', fname)
+ from_list = 0
+ else:
+ fname = os.path.join(self.Path('alt_path'),
+ os.path.basename(filename))
+ from_list = 1
+ elif mode == "check":
+ dlg = altpathdialog.AltPathConfirmDialog(filename)
+ fname = dlg.RunDialog()
+ if fname is not None:
+ self.SetPath('alt_path', fname)
+ from_list = 0
+ else:
+ fname = None
+ from_list = 0
+ return fname, from_list
+
+
+ def SaveSession(self):
+ save_session(self.session, self.session.filename)
+
+ def maps_changed(self, *args):
+ """Subscribed to the session's MAPS_CHANGED messages.
+
+ Set the toplevel window's map to the map in the session. This is
+ done by calling the window's SetMap method with the map as
+ argument. If the session doesn't have any maps None is used
+ instead.
+
+ Currently Thuban can only really handle at most one map in a
+ sessions so the first map in the session's list of maps as
+ returned by the Maps method is used.
+ """
+ # The mainwindow may not have been created yet, so check whether
+ # it has been created before calling any of its methods
+ if self.top is not None:
+ if self.session.HasMaps():
+ self.top.SetMap(self.session.Maps()[0])
+ else:
+ self.top.SetMap(None)
+
+ in_exception_dialog = 0 # flag: are we already inside the exception dialog?
+
+ def ShowExceptionDialog(self, exc_type, exc_value, exc_traceback):
+ """Show a message box with information about an exception.
+
+ The parameters are the usual values describing an exception in
+ Python, the exception type, the value and the traceback.
+
+ This method can be used as a value for the sys.excepthook.
+ """
+
+ if self.in_exception_dialog:
+ return
+ self.in_exception_dialog = 1
+ while wx.IsBusy():
+ wx.EndBusyCursor() # reset the mouse cursor
+
+ try:
+ lines = traceback.format_exception(exc_type, exc_value,
+ exc_traceback)
+ message = _("An unhandled exception occurred:\n%s\n"
+ "(please report to"
+ " http://thuban.intevation.org/bugtracker.html)"
+ "\n\n%s") % (exc_value, "".join(lines))
+ print message
+
+ # We don't use an explicit parent here because this method might
+ # be called in circumstances where the main window doesn't exist
+ # anymore.
+ exceptiondialog.run_exception_dialog(None, message)
+
+ finally:
+ self.in_exception_dialog = 0
+ # delete the last exception info that python keeps in
+ # sys.last_* because especially last_traceback keeps
+ # indirect references to all objects bound to local
+ # variables and this might prevent some object from being
+ # collected early enough.
+ sys.last_type = sys.last_value = sys.last_traceback = None
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/baserenderer.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/baserenderer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/baserenderer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,601 @@
+# Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jonathan Coles <jonathan at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Basic rendering logic for Thuban maps
+
+The code in this module is completely independend of wx so that it can
+be tested reasonably easily and it could make it easier to write non-wx
+renderers.
+"""
+
+from __future__ import generators
+
+__version__ = "$Revision: 2718 $"
+# $Source$
+# $Id: baserenderer.py 2718 2007-01-05 23:43:49Z dpinte $
+
+import sys
+import traceback
+
+from Thuban.Model.layer import Layer, RasterLayer
+from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POINT
+from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
+ ALIGN_LEFT, ALIGN_RIGHT
+
+import Thuban.Model.resource
+
+
+
+#
+# Renderer Extensions
+#
+# The renderer extensions provide a way to render layer types defined in
+# Thuban extensions. The renderer extensions are stored as a list with
+# (layer_class, draw_function) pairs. If the renderer has to draw a
+# non-builtin layer type, i.e. a layer that is not a subclass of Layer
+# or RasterLayer, it iterates through that list, tests whether the layer
+# to be drawn is an instance of layer_class and if so calls
+# draw_function with the renderer and the layer as arguments. Since
+# drawing is done incrementally, the draw_function should return an
+# iterable. The easiest way is to simply implement the draw_function as
+# a generator and to yield in suitable places, or to return the empty
+# tuple.
+#
+# New renderer extensions should be added with add_renderer_extension().
+# If necessary the extensions list can be reset with
+# init_renderer_extensions().
+
+_renderer_extensions = []
+
+def add_renderer_extension(layer_class, function):
+ """Add a renderer extension for the layer class layer_class
+
+ When an instance of layer_class is to be drawn by the renderer the
+ renderer will call function with the renderer and the layer_class
+ instance as arguments. Since drawing is done incrementally, the
+ function should return an iterable. The easiest way is to simply
+ implement the draw_function as a generator and to yield True in
+ suitable places, or to return the empty tuple if it's not possible
+ to do the rendering incrementally.
+ """
+ _renderer_extensions.append((layer_class, function))
+
+def init_renderer_extensions():
+ """(Re)initialize the list of renderer extensions
+
+ Calling this function outside of the test suite is probably not
+ useful.
+ """
+ del _renderer_extensions[:]
+
+def proj_params_to_str(proj):
+ "Build a string suitable for GDAL describing the given projection"
+ str = ""
+ if proj is not None:
+ for p in proj.GetAllParameters():
+ str += "+" + p + " "
+ return str
+
+#
+# Base Renderer
+#
+
+class BaseRenderer:
+
+ """Basic Renderer Infrastructure for Thuban Maps
+
+ This class can't be used directly to render because it doesn't know
+ anything about real DCs such as how to create pens or brushes. That
+ functionality has to be provided by derived classes. The reason for
+ this is that it makes the BaseRenderer completely independend of wx
+ and thus it's quite easy to write test cases for it.
+ """
+ # If true the render honors the visibility flag of the layers
+ honor_visibility = 1
+
+ # Transparent brushes and pens. Derived classes should define these
+ # as appropriate.
+ TRANSPARENT_PEN = None
+ TRANSPARENT_BRUSH = None
+
+ def __init__(self, dc, map, scale, offset, region = None,
+ resolution = 72.0, honor_visibility = None):
+ """Inititalize the renderer.
+
+ dc -- the device context to render on.
+
+ scale, offset -- the scale factor and translation to convert
+ between projected coordinates and the DC coordinates
+
+ region -- The region to draw as a (x, y, width, height) tuple in
+ the map's coordinate system. Default is None meaning
+ to draw everything.
+
+ resolution -- the assumed resolution of the DC. Used to convert
+ absolute lengths like font sizes to DC coordinates. The
+ default is 72.0. If given, this parameter must be
+ provided as a keyword argument.
+
+ honor_visibility -- boolean. If true, honor the visibility flag
+ of the layers, otherwise draw all layers. If None (the
+ default), use the renderer's default. If given, this
+ parameter must be provided as a keyword argument.
+ """
+ # resolution in pixel/inch
+ self.dc = dc
+ self.map = map
+ self.scale = scale
+ self.offset = offset
+ self.region = region
+ if honor_visibility is not None:
+ self.honor_visibility = honor_visibility
+ # store the resolution in pixel/point because it's more useful
+ # later.
+ self.resolution = resolution / 72.0
+
+ def tools_for_property(self, prop):
+ """Return a suitable pen and brush for the property
+
+ This method must be implemented in derived classes. The return
+ value should be a tuple (pen, brush).
+ """
+ raise NotImplementedError
+
+ def render_map(self):
+ """Render the map onto the DC.
+
+ Both map and DC are the ones the renderer was instantiated with.
+
+ This method is just a front-end for render_map_incrementally
+ which does all rendering in one go. It also calls the dc's
+ BeginDrawing and EndDrawing methods before and after calling
+ render_map_incrementally.
+ """
+
+ self.dc.BeginDrawing()
+ try:
+ for cont in self.render_map_incrementally():
+ pass
+ finally:
+ self.dc.EndDrawing()
+
+ def render_map_incrementally(self):
+ """Render the map incrementally.
+
+ Return an iterator whose next method should be called until it
+ returns False. After returning False it will raise StopIteration
+ so that you could also use it in a for loop (implementation
+ detail: this method is implemented as a generator).
+
+ Iterate through all layers and draw them. Layers containing
+ vector data are drawn with the draw_shape_layer method, raster
+ layers are drawn with draw_raster_layer. The label layer is
+ drawn last with draw_label_layer.
+
+ During execution of this method, the map is bound to self.map so
+ that methods especially in derived classes have access to the
+ map if necessary.
+ """
+
+ for layer in self.map.Layers():
+ # if honor_visibility is true, only draw visible layers,
+ # otherwise draw all layers
+ if not self.honor_visibility or layer.Visible():
+ if isinstance(layer, Layer):
+ for i in self.draw_shape_layer_incrementally(layer):
+ yield True
+ elif isinstance(layer, RasterLayer):
+ self.draw_raster_layer(layer)
+ yield True
+ else:
+ # look it up in the renderer extensions
+ for cls, func in _renderer_extensions:
+ if isinstance(layer, cls):
+ for i in func(self, layer):
+ yield True
+ break
+ else:
+ # No renderer found. Print a message about it
+ print >>sys.stderr, ("Drawing layer %r not supported"
+ % layer)
+ yield True
+
+ self.draw_label_layer(self.map.LabelLayer())
+ yield False
+
+ def draw_shape_layer_incrementally(self, layer):
+ """Draw the shape layer layer onto the map incrementally.
+
+ This method is a generator which yields True after every 500
+ shapes.
+ """
+ scale = self.scale
+ offx, offy = self.offset
+
+ map_proj = self.map.projection
+ layer_proj = layer.projection
+
+ brush = self.TRANSPARENT_BRUSH
+ pen = self.TRANSPARENT_PEN
+
+ old_prop = None
+ old_group = None
+ lc = layer.GetClassification()
+ field = layer.GetClassificationColumn()
+ defaultGroup = lc.GetDefaultGroup()
+ table = layer.ShapeStore().Table()
+
+ if lc.GetNumGroups() == 0:
+ # There's only the default group, so we can pretend that
+ # there is no field to classifiy on which makes things
+ # faster since we don't need the attribute information at
+ # all.
+ field = None
+
+ # Determine which render function to use.
+ useraw, draw_func, draw_func_param = self.low_level_renderer(layer)
+
+ #
+ # Iterate through all shapes that have to be drawn.
+ #
+
+ # Count the shapes drawn so that we can yield every few hundred
+ # shapes
+ count = 0
+
+ # Cache the tools (pens and brushes) for the classification
+ # groups. This is a mapping from the group's ids to the a tuple
+ # (pen, brush)
+ tool_cache = {}
+
+ for shape in self.layer_shapes(layer):
+ count += 1
+ if field is None:
+ group = defaultGroup
+ else:
+ value = table.ReadValue(shape.ShapeID(), field)
+ group = lc.FindGroup(value)
+
+ if not group.IsVisible():
+ continue
+
+ try:
+ pen, brush = tool_cache[id(group)]
+ except KeyError:
+ pen, brush = tool_cache[id(group)] \
+ = self.tools_for_property(group.GetProperties())
+
+ if useraw:
+ data = shape.RawData()
+ else:
+ data = shape.Points()
+ if draw_func == self.draw_point_shape:
+ draw_func(draw_func_param, data, pen, brush,
+ size = group.GetProperties().GetSize())
+ else:
+ draw_func(draw_func_param, data, pen, brush)
+ if count % 500 == 0:
+ yield True
+
+ def layer_shapes(self, layer):
+ """Return an iterable over the shapes to be drawn from the given layer.
+
+ The default implementation simply returns all ids in the layer.
+ Override in derived classes to be more precise.
+ """
+ return layer.ShapeStore().AllShapes()
+
+ def low_level_renderer(self, layer):
+ """Return the low-level renderer for the layer for draw_shape_layer
+
+ The low level renderer to be returned by this method is a tuple
+ (useraw, func, param) where useraw is a boolean indicating
+ whether the function uses the raw shape data, func is a callable
+ object and param is passed as the first parameter to func. The
+ draw_shape_layer method will call func like this:
+
+ func(param, shapedata, pen, brush)
+
+ where shapedata is the return value of the RawData method of the
+ shape object if useraw is true or the return value of the Points
+ method if it's false. pen and brush are the pen and brush to use
+ to draw the shape on the dc.
+
+ The default implementation returns one of
+ self.draw_polygon_shape, self.draw_arc_shape or
+ self.draw_point_shape as func and layer as param. None of the
+ method use the raw shape data. Derived classes can override this
+ method to return more efficient low level renderers.
+ """
+ shapetype = layer.ShapeType()
+ if shapetype == SHAPETYPE_POINT:
+ func = self.draw_point_shape
+ elif shapetype == SHAPETYPE_ARC:
+ func = self.draw_arc_shape
+ else:
+ func = self.draw_polygon_shape
+ return False, func, layer
+
+ def make_point(self, x, y):
+ """Convert (x, y) to a point object.
+
+ Derived classes must override this method.
+ """
+ raise NotImplementedError
+
+ def projected_points(self, layer, points):
+ """Return the projected coordinates of the points taken from layer.
+
+ Transform all the points in the list of lists of coordinate
+ pairs in points.
+
+ The transformation applies the inverse of the layer's projection
+ if any, then the map's projection if any and finally applies
+ self.scale and self.offset.
+
+ The returned list has the same structure as the one returned the
+ shape's Points method.
+ """
+ proj = self.map.GetProjection()
+ if proj is not None:
+ forward = proj.Forward
+ else:
+ forward = None
+ proj = layer.GetProjection()
+ if proj is not None:
+ inverse = proj.Inverse
+ else:
+ inverse = None
+ result = []
+ scale = self.scale
+ offx, offy = self.offset
+ make_point = self.make_point
+
+ for part in points:
+ result.append([])
+ for x, y in part:
+ if inverse:
+ x, y = inverse(x, y)
+ if forward:
+ x, y = forward(x, y)
+ result[-1].append(make_point(x * scale + offx,
+ -y * scale + offy))
+ return result
+
+ def draw_polygon_shape(self, layer, points, pen, brush):
+ """Draw a polygon shape from layer with the given brush and pen
+
+ The shape is given by points argument which is a the return
+ value of the shape's Points() method. The coordinates in the
+ DC's coordinate system are determined with
+ self.projected_points.
+
+ For a description of the algorithm look in wxproj.cpp.
+ """
+ points = self.projected_points(layer, points)
+
+ if brush is not self.TRANSPARENT_BRUSH:
+ polygon = []
+ for part in points:
+ polygon.extend(part)
+
+ # missing back vertices for correct filling.
+ insert_index = len(polygon)
+ for part in points[:-1]:
+ polygon.insert(insert_index, part[0])
+
+ self.dc.SetBrush(brush)
+ self.dc.SetPen(self.TRANSPARENT_PEN)
+ self.dc.DrawPolygon(polygon)
+
+ if pen is not self.TRANSPARENT_PEN:
+ # At last draw the boundarys of the simple polygons
+ self.dc.SetBrush(self.TRANSPARENT_BRUSH)
+ self.dc.SetPen(pen)
+ for part in points:
+ self.dc.DrawLines(part)
+
+ def draw_arc_shape(self, layer, points, pen, brush):
+ """Draw an arc shape from layer with the given brush and pen
+
+ The shape is given by points argument which is a the return
+ value of the shape's Points() method. The coordinates in the
+ DC's coordinate system are determined with
+ self.projected_points.
+ """
+ points = self.projected_points(layer, points)
+ self.dc.SetBrush(brush)
+ self.dc.SetPen(pen)
+ for part in points:
+ self.dc.DrawLines(part)
+
+ def draw_point_shape(self, layer, points, pen, brush, size = 5):
+ """Draw a point shape from layer with the given brush and pen
+
+ The shape is given by points argument which is a the return
+ value of the shape's Points() method. The coordinates in the
+ DC's coordinate system are determined with
+ self.projected_points.
+
+ The point is drawn as a circle centered on the point.
+ """
+ points = self.projected_points(layer, points)
+ if not points:
+ return
+
+ radius = int(round(self.resolution * size))
+ self.dc.SetBrush(brush)
+ self.dc.SetPen(pen)
+ for part in points:
+ for p in part:
+ self.dc.DrawEllipse(p.x - radius, p.y - radius,
+ 2 * radius, 2 * radius)
+
+ def draw_raster_layer(self, layer):
+ """Draw the raster layer
+
+ This implementation uses self.projected_raster_layer() to project
+ and scale the data as required by the layer's and map's projections
+ and the scale and offset of the renderer and then hands the transformed
+ data to self.draw_raster_data() which has to be implemented in
+ derived classes.
+ """
+ offx, offy = self.offset
+ width, height = self.dc.GetSizeTuple()
+
+ in_proj = proj_params_to_str(layer.GetProjection())
+ out_proj = proj_params_to_str(self.map.GetProjection())
+
+ # True -- warp the image to the size of the whole screen
+ # False -- only use the bound box of the layer (currently inaccurate)
+ if True:
+ #if False:
+ pmin = [0,height]
+ pmax = [width, 0]
+ else:
+ bb = layer.LatLongBoundingBox()
+ bb = [[[bb[0], bb[1]], [bb[2], bb[3]],],]
+ pmin, pmax = self.projected_points(layer, bb)[0]
+
+ #print bb
+ #print pmin, pmax
+
+ fmin = [max(0, min(pmin[0], pmax[0])) - offx,
+ offy - min(height, max(pmin[1], pmax[1]))]
+
+ fmax = [min(width, max(pmin[0], pmax[0])) - offx,
+ offy - max(0, min(pmin[1], pmax[1]))]
+
+ xmin = fmin[0]/self.scale
+ ymin = fmin[1]/self.scale
+ xmax = fmax[0]/self.scale
+ ymax = fmax[1]/self.scale
+
+ width = int(min(width, round(fmax[0] - fmin[0] + 1)))
+ height = int(min(height, round(fmax[1] - fmin[1] + 1)))
+
+ options = 0
+ options = options | layer.MaskType()
+
+ img_data = self.projected_raster_layer(layer, in_proj, out_proj,
+ (xmin,ymin,xmax,ymax), [0,0], (width, height), options)
+
+ if img_data is not None:
+ data = (width, height, img_data)
+ self.draw_raster_data(fmin[0]+offx, offy-fmax[1],
+ data, format="RAW", opacity=layer.Opacity())
+ data = None
+
+ def projected_raster_layer(self, layer, srcProj, dstProj, extents,
+ resolution, dimensions, options):
+ """Return the projected raster image associated with the layer.
+
+ The returned value will be a tuple of the form
+
+ (image_data, mask_data, alpha_data)
+
+ suitable for the data parameter to draw_raster_data.
+
+ The return value may be None if raster projections are not supported.
+
+ srcProj -- a string describing the source projection
+ dstProj -- a string describing the destination projection
+ extents -- a tuple of the region to project in map coordinates
+ resolution -- (currently not used, defaults to [0,0])
+ dimensions -- a tuple (width, height) for the output image
+ options -- bit-wise options to pass to the renderer
+
+ the currently supported values for options are
+
+ OPTS_MASK = 1 -- generate a mask
+ OPTS_ALPHA = 2 -- generate an alpha channel
+ OPTS_INVERT_MASK = 4 -- invert the values in the mask
+ (if generated)
+
+ This method has to be implemented by derived classes.
+ """
+
+ raise NotImplementedError
+
+ def draw_raster_data(self, x, y, data, format="BMP", opacity=1.0):
+ """Draw a raster image held in data onto the DC with the top
+ left corner at (x,y)
+
+ The raster image data is a tuple of the form
+ (width, height, (image_data, mask_data, alpha_data))
+
+ holding the image width, height, image data, mask data, and alpha data.
+ mask_data may be None if a mask should not be used. alpha_data may
+ also be None. If both are not None mask overrides alpha. If
+ format is 'RAW' the data will be RGB values and the mask
+ will be in XMB format. Otherwise, both kinds
+ of data are assumed to be in the format specified in format.
+
+ The format parameter is a string with the name of the format.
+ The following format names should be used:
+
+ 'RAW' -- an array of RGB values (len=3*width*height)
+ 'PNG' -- Portable Network Graphic (transparency supported)
+ 'BMP' -- Windows Bitmap
+ 'TIFF' -- Tagged Image File Format
+ 'GIF' -- GIF Image
+ 'JPEG' -- JPEG Image
+
+ The default format is 'BMP'.
+
+ This method has to be implemented by derived classes. The
+ implementation in the derived class should try to support at
+ least the formats specified above and may support more.
+ """
+ raise NotImplementedError
+
+ def label_font(self):
+ """Return the font object for the label layer"""
+ raise NotImplementedError
+
+ def draw_label_layer(self, layer):
+ """Draw the label layer
+
+ All labels are draw in the font returned by self.label_font().
+ """
+ scale = self.scale
+ offx, offy = self.offset
+
+ self.dc.SetFont(self.label_font())
+
+ map_proj = self.map.projection
+ if map_proj is not None:
+ forward = map_proj.Forward
+ else:
+ forward = None
+
+ for label in layer.Labels():
+ x = label.x
+ y = label.y
+ text = label.text
+ if forward:
+ x, y = forward(x, y)
+ x = int(round(x * scale + offx))
+ y = int(round(-y * scale + offy))
+ width, height = self.dc.GetTextExtent(text.decode('iso-8859-1'))
+ if label.halign == ALIGN_LEFT:
+ # nothing to be done
+ pass
+ elif label.halign == ALIGN_RIGHT:
+ x = x - width
+ elif label.halign == ALIGN_CENTER:
+ x = x - width/2
+ if label.valign == ALIGN_TOP:
+ # nothing to be done
+ pass
+ elif label.valign == ALIGN_BOTTOM:
+ y = y - height
+ elif label.valign == ALIGN_CENTER:
+ y = y - height/2
+ self.dc.DrawText(text.decode('iso-8859-1'), x, y)
Added: packages/thuban/branches/upstream/current/Thuban/UI/classgen.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/classgen.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/classgen.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1003 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""The Classification Generator Dialog"""
+
+__version__ = "$Revision: 2709 $"
+# $Source$
+# $Id: classgen.py 2709 2006-10-03 09:34:51Z dpinte $
+
+
+import sys
+
+import wx
+
+from Thuban import _
+
+from Thuban.Model.classification import ClassGroupProperties
+
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
+ FIELDTYPE_STRING
+
+from Thuban.Model.layer import SHAPETYPE_ARC
+from Thuban.Model.range import Range
+from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+
+import classifier, resource
+
+from Thuban.Model.classgen import \
+ generate_uniform_distribution, generate_singletons, generate_quantiles, \
+ CustomRamp, grey_ramp, red_ramp, green_ramp, blue_ramp, green_to_red_ramp, \
+ HotToColdRamp, FixedRamp
+
+
+USEALL_BMP = "group_use_all"
+USE_BMP = "group_use"
+USENOT_BMP = "group_use_not"
+USENONE_BMP = "group_use_none"
+
+GENCOMBOSTR_UNIFORM = _("Uniform Distribution")
+GENCOMBOSTR_UNIQUE = _("Unique Values")
+GENCOMBOSTR_QUANTILES = _("Quantiles from Table")
+
+PROPCOMBOSTR_CUSTOM = _("Custom Ramp")
+PROPCOMBOSTR_GREY = _("Grey Ramp")
+PROPCOMBOSTR_RED = _("Red Ramp")
+PROPCOMBOSTR_GREEN = _("Green Ramp")
+PROPCOMBOSTR_BLUE = _("Blue Ramp")
+PROPCOMBOSTR_GREEN2RED = _("Green-to-Red Ramp")
+PROPCOMBOSTR_HOT2COLD = _("Hot-to-Cold Ramp")
+
+ID_CLASSGEN_GENCOMBO = 4007
+ID_CLASSGEN_PROPCOMBO = 4008
+
+ID_BORDER_COLOR = 4009
+ID_BORDER_COLOR_CHANGE = 4010
+
+class ClassGenDialog(wx.Dialog):
+
+ def __init__(self, parent, layer, fieldName):
+ """Inialize the class generating dialog.
+
+ parent -- this must be an instance of the Classifier class
+ """
+
+ wx.Dialog.__init__(self, parent, -1, _("Generate Classification"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+
+ self.parent = parent
+ self.layer = layer
+ self.clazz = None
+
+ col = layer.ShapeStore().Table().Column(fieldName)
+ self.type = col.type
+
+ self.fieldName = fieldName
+ self.fieldType = self.type
+
+ self.curGenPanel = None
+
+ self.genpanels = []
+
+ #############
+ # we need to create genButton first because when we create the
+ # panels they will call AllowGenerate() which uses genButton.
+ #
+ self.genButton = wx.Button(self, wx.ID_OK, _("Generate"))
+ self.cancelButton = wx.Button(self, wx.ID_CANCEL, _("Close"))
+ self.genButton.SetDefault()
+
+ self.genChoice = wx.Choice(self, ID_CLASSGEN_GENCOMBO)
+
+ self.genpanels.append((GENCOMBOSTR_UNIQUE, GenUniquePanel))
+ if self.type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
+ self.genpanels.append((GENCOMBOSTR_UNIFORM, GenUniformPanel))
+ self.genpanels.append((GENCOMBOSTR_QUANTILES, GenQuantilesPanel))
+
+ for name, clazz in self.genpanels:
+ self.genChoice.Append(name, [clazz, None])
+
+ self.genChoice.SetSelection(0)
+
+ for i in range(self.genChoice.GetCount()):
+ clazz, obj = self.genChoice.GetClientData(i)
+
+ if obj is None:
+ obj = clazz(self, self.layer, self.fieldName, self.fieldType)
+ obj.Hide()
+ self.genChoice.SetClientData(i, [clazz, obj])
+
+
+ #############
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ sizer.Add(wx.StaticText(self, -1, _("Field: %s") % fieldName),
+ 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(
+ self, -1,
+ _("Data Type: %s") % classifier.Classifier.type2string[self.type]),
+ 0, wx.ALL, 4)
+
+ psizer = wx.BoxSizer(wx.HORIZONTAL)
+ psizer.Add(wx.StaticText(self, -1, _("Generate:")),
+ 0, wx.ALIGN_CENTER_VERTICAL, 0)
+ psizer.Add(self.genChoice, 1, wx.ALL | wx.GROW, 4)
+
+ sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
+
+ self.sizer_genPanel = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(self.sizer_genPanel, 1, wx.GROW | wx.ALL, 4)
+
+ psizer = wx.BoxSizer(wx.HORIZONTAL)
+ psizer.Add(wx.StaticText(self, -1, _("Color Scheme:")),
+ 0, wx.ALIGN_CENTER_VERTICAL, 0)
+
+ # Properties (Ramp) ComboBox
+ self.propCombo = wx.Choice(self, ID_CLASSGEN_PROPCOMBO)
+
+ self.propPanel = None
+ custom_ramp_panel = CustomRampPanel(self, layer.ShapeType())
+
+ self.propCombo.Append(PROPCOMBOSTR_GREY, grey_ramp)
+ self.propCombo.Append(PROPCOMBOSTR_RED, red_ramp)
+ self.propCombo.Append(PROPCOMBOSTR_GREEN, green_ramp)
+ self.propCombo.Append(PROPCOMBOSTR_BLUE, blue_ramp)
+ self.propCombo.Append(PROPCOMBOSTR_GREEN2RED, green_to_red_ramp)
+ self.propCombo.Append(PROPCOMBOSTR_HOT2COLD, HotToColdRamp())
+ self.propCombo.Append(PROPCOMBOSTR_CUSTOM, custom_ramp_panel)
+
+ self.propCombo.SetSelection(0)
+
+ psizer.Add(self.propCombo, 1, wx.ALL | wx.GROW, 4)
+ sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
+
+ if layer.ShapeType() != SHAPETYPE_ARC:
+ psizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.fix_border_check = wx.CheckBox(self, -1, _("Fix Border Color"))
+ psizer.Add(self.fix_border_check, 0, wx.ALL | wx.GROW, 4)
+ self.border_color = classifier.ClassGroupPropertiesCtrl(
+ self, ID_BORDER_COLOR,
+ ClassGroupProperties(), SHAPETYPE_ARC,
+ style=wx.SIMPLE_BORDER, size=(40, 20))
+ psizer.Add(self.border_color, 0, wx.ALL | wx.GROW, 4)
+ psizer.Add(wx.Button(self, ID_BORDER_COLOR_CHANGE, _("Change")),
+ 0, wx.ALL, 4)
+ sizer.Add(psizer, 0, wx.ALL | wx.GROW, 4)
+ self.Bind(wx.EVT_BUTTON, self.OnBorderColorChange, id=ID_BORDER_COLOR_CHANGE)
+ else:
+ self.border_color = None
+
+ sizer.Add(custom_ramp_panel, 1, wx.GROW | wx.ALL, 4)
+ sizer.Show(custom_ramp_panel, False)
+
+ # Finally place the main buttons
+ buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
+ buttonSizer.Add(self.genButton, 0, wx.RIGHT|wx.EXPAND, 10)
+ buttonSizer.Add(self.cancelButton, 0, wx.RIGHT|wx.EXPAND, 10)
+ sizer.Add(buttonSizer, 0, wx.ALIGN_RIGHT|wx.BOTTOM|wx.TOP, 10)
+
+ self.SetSizer(sizer)
+ self.SetAutoLayout(True)
+ sizer.SetSizeHints(self)
+
+ self.topBox = sizer
+
+ self.__DoOnGenTypeSelect()
+
+ self.Bind(wx.EVT_CHOICE, self._OnGenTypeSelect, id=ID_CLASSGEN_GENCOMBO)
+ self.Bind(wx.EVT_CHOICE, self._OnPropTypeSelect, id=ID_CLASSGEN_PROPCOMBO)
+ self.Bind(wx.EVT_BUTTON, self.OnOK, self.genButton)
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelButton)
+
+ self.__DoOnGenTypeSelect()
+
+ self.genChoice.SetFocus()
+
+ def GetClassification(self):
+ return self.clazz
+
+ def AllowGenerate(self, on):
+ pass #self.genButton.Enable(on)
+
+ def OnOK(self, event):
+ """This is really the generate button, but we want to override
+ the wxDialog class.
+ """
+
+ index = self.genChoice.GetSelection()
+
+ assert index != -1, "button should be disabled!"
+
+ genSel = self.genChoice.GetString(index)
+ clazz, genPanel = self.genChoice.GetClientData(index)
+
+ propPanel = self.propPanel
+
+ if genSel in (GENCOMBOSTR_UNIFORM, \
+ GENCOMBOSTR_UNIQUE, \
+ GENCOMBOSTR_QUANTILES):
+
+ numGroups = genPanel.GetNumGroups()
+
+ index = self.propCombo.GetSelection()
+
+ propSel = self.propCombo.GetString(index)
+ propPanel = self.propCombo.GetClientData(index)
+
+ ramp = propPanel.GetRamp()
+ if self.border_color and self.fix_border_check.IsChecked():
+ props = self.border_color.GetProperties()
+ ramp = FixedRamp(ramp,
+ (props.GetLineColor(), props.GetLineWidth(), None))
+
+ if genSel == GENCOMBOSTR_UNIFORM:
+
+ min = genPanel.GetMin()
+ max = genPanel.GetMax()
+
+ if min is not None \
+ and max is not None \
+ and numGroups is not None:
+
+ self.clazz = generate_uniform_distribution(
+ min, max, numGroups, ramp,
+ self.type == FIELDTYPE_INT)
+
+ self.parent._SetClassification(self.clazz)
+
+ elif genSel == GENCOMBOSTR_UNIQUE:
+
+ list = genPanel.GetValueList()
+
+ if len(list) > 0:
+ self.clazz = generate_singletons(list, ramp)
+ self.parent._SetClassification(self.clazz)
+
+ elif genSel == GENCOMBOSTR_QUANTILES:
+
+ _range = genPanel.GetRange()
+ _list = genPanel.GetList()
+ _list.sort()
+
+ delta = 1 / float(numGroups)
+ percents = [delta * i for i in range(1, numGroups + 1)]
+ adjusted, self.clazz = \
+ generate_quantiles(_list, percents, ramp, _range)
+
+ if adjusted:
+ dlg = wx.MessageDialog(self,
+ _("Based on the data from the table and the input\n"
+ "values, the exact quantiles could not be generated.\n\n"
+ "Accept a close estimate?"),
+ _("Problem with Quantiles"),
+
+ wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
+ if dlg.ShowModal() == wx.ID_YES:
+ self.parent._SetClassification(self.clazz)
+ else:
+ self.parent._SetClassification(self.clazz)
+
+ def OnCancel(self, event):
+ self.Close()
+
+ def OnBorderColorChange(self, event):
+ self.border_color.DoEdit()
+
+ def _OnGenTypeSelect(self, event):
+ self.__DoOnGenTypeSelect()
+ return
+
+ combo = event.GetEventObject()
+
+ selIndex = combo.GetSelection()
+
+ if self.genPanel is not None:
+ self.topBox.Show(self.genPanel, False)
+
+ self.genPanel = combo.GetClientData(selIndex)
+ if self.genPanel is not None:
+ self.topBox.Show(self.genPanel, True)
+
+ self.topBox.SetSizeHints(self)
+ self.topBox.Layout()
+
+ def _OnPropTypeSelect(self, event):
+ combo = event.GetEventObject()
+
+ selIndex = combo.GetSelection()
+ sel = combo.GetString(selIndex)
+
+ if isinstance(self.propPanel, wx.Panel):
+ self.topBox.Show(self.propPanel, False)
+
+ self.propPanel = combo.GetClientData(selIndex)
+
+ if isinstance(self.propPanel, wx.Panel):
+ self.topBox.Show(self.propPanel, True)
+
+ self.topBox.SetSizeHints(self)
+ self.topBox.Layout()
+
+ def __DoOnGenTypeSelect(self):
+ choice = self.genChoice
+
+ sel = choice.GetSelection()
+ if sel == -1: return
+
+ clazz, obj = choice.GetClientData(sel)
+
+ if self.curGenPanel is not None:
+ self.curGenPanel.Hide()
+ self.sizer_genPanel.Remove(self.curGenPanel)
+
+ self.curGenPanel = obj
+ self.curGenPanel.Show()
+
+ self.sizer_genPanel.Add(self.curGenPanel, 1,
+ wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3)
+ self.sizer_genPanel.Layout()
+ self.Layout()
+ self.topBox.SetSizeHints(self)
+
+ID_UNIFORM_MIN = 4001
+ID_UNIFORM_MAX = 4002
+ID_UNIFORM_NGROUPS = 4003
+ID_UNIFORM_STEP = 4004
+ID_UNIFORM_RETRIEVE = 4005
+
+class GenUniformPanel(wx.Panel):
+
+ def __init__(self, parent, layer, fieldName, fieldType):
+ wx.Panel.__init__(self, parent, -1)
+
+ self.parent = parent
+ self.layer = layer
+ self.fieldName = fieldName
+ self.fieldType = fieldType
+
+ topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
+ wx.VERTICAL)
+
+ #############
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ sizer.Add(wx.StaticText(self, -1, _("Min:")), 0, wx.ALL, 4)
+ self.minCtrl = wx.TextCtrl(self, ID_UNIFORM_MIN, style=wx.TE_RIGHT)
+ sizer.Add(self.minCtrl, 1, wx.ALL, 4)
+ self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MIN)
+
+ sizer.Add(wx.StaticText(self, -1, _("Max:")), 0, wx.ALL, 4)
+ self.maxCtrl = wx.TextCtrl(self, ID_UNIFORM_MAX, style=wx.TE_RIGHT)
+ sizer.Add(self.maxCtrl, 1, wx.ALL, 4)
+ self.Bind(wx.EVT_TEXT, self._OnRangeChanged, id=ID_UNIFORM_MAX)
+
+ sizer.Add(wx.Button(self, ID_UNIFORM_RETRIEVE, _("Retrieve From Table")),
+ 0, wx.ALL, 4)
+ self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIFORM_RETRIEVE)
+
+ topSizer.Add(sizer, 1, wx.GROW, 0)
+
+ #############
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ sizer.Add(wx.StaticText(self, -1, _("Number of Groups:")), 0, wx.ALL, 4)
+ self.numGroupsCtrl = wx.SpinCtrl(self, ID_UNIFORM_NGROUPS,
+ style=wx.TE_RIGHT)
+ self.Bind(wx.EVT_TEXT, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
+ self.Bind(wx.EVT_SPINCTRL, self._OnNumGroupsChanged, id=ID_UNIFORM_NGROUPS)
+ sizer.Add(self.numGroupsCtrl, 1, wx.ALL, 4)
+
+ sizer.Add(wx.StaticText(self, -1, _("Stepping:")), 0, wx.ALL, 4)
+ self.stepCtrl = wx.TextCtrl(self, ID_UNIFORM_STEP, style=wx.TE_RIGHT)
+ self.Bind(wx.EVT_TEXT, self._OnSteppingChanged, id=ID_UNIFORM_STEP)
+ sizer.Add(self.stepCtrl , 1, wx.ALL, 4)
+
+ topSizer.Add(sizer, 1, wx.GROW, 0)
+
+ #############
+
+ self.SetSizer(topSizer)
+ self.SetAutoLayout(True)
+ topSizer.SetSizeHints(self)
+
+ self.numGroupsChanging = False
+ self.steppingChanging = False
+
+ self.numGroupsCtrl.SetRange(1, sys.maxint)
+
+ self.numGroupsCtrl.SetValue(1)
+ self.stepCtrl.SetValue("1")
+ self.maxCtrl.SetValue("0")
+ self.minCtrl.SetValue("0")
+ self.minCtrl.SetFocus()
+
+ def GetNumGroups(self):
+ value = self.numGroupsCtrl.GetValue()
+ return self.__GetValidatedTypeEntry(self.numGroupsCtrl,
+ value,
+ FIELDTYPE_INT,
+ None)
+
+ def GetStepping(self):
+ step = self.stepCtrl.GetValue()
+ return self.__GetValidatedTypeEntry(self.stepCtrl,
+ step,
+ self.fieldType,
+ 0)
+
+ def GetMin(self):
+ min = self.minCtrl.GetValue()
+ max = self.maxCtrl.GetValue()
+ return self.__GetValidatedTypeEntry(self.minCtrl,
+ min,
+ self.fieldType,
+ max)
+
+ def GetMax(self):
+ min = self.minCtrl.GetValue()
+ max = self.maxCtrl.GetValue()
+ return self.__GetValidatedTypeEntry(self.maxCtrl,
+ max,
+ self.fieldType,
+ min)
+
+ def _OnRangeChanged(self, event):
+
+ hasFocus = wx.Window_FindFocus() == event.GetEventObject()
+ min = self.GetMin()
+ max = self.GetMax()
+
+ on = min is not None \
+ and max is not None
+
+ self.numGroupsCtrl.Enable(on)
+ self.stepCtrl.Enable(on)
+
+ ngroups = self.GetNumGroups()
+
+ if ngroups is not None \
+ and min is not None \
+ and max is not None \
+ and ngroups != 0:
+
+ #self.stepCtrl.SetValue(str((max - min) / ngroups))
+ self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
+ #self.numGroupsCtrl.SetValue(ngroups)
+
+ self.parent.AllowGenerate(self.GetStepping() is not None)
+ else:
+ self.parent.AllowGenerate(False)
+
+
+ if hasFocus:
+ event.GetEventObject().SetFocus()
+
+ def _OnNumGroupsChanged(self, event):
+ if self.steppingChanging:
+ self.steppingChanging = False
+ return
+
+
+ obj = event.GetEventObject()
+ ngroups = self.GetNumGroups()
+ min = self.GetMin()
+ max = self.GetMax()
+
+ if ngroups is not None \
+ and min is not None \
+ and max is not None \
+ and ngroups != 0:
+
+ #
+ # changing the value in the stepCtrl sends an event
+ # that the control is changing, at which point
+ # we try to update the numGroupsCtrl. This causes
+ # an infinite recursion. This flag and the one
+ # called steppingChanging tries to prevent the recursion.
+ #
+ self.numGroupsChanging = True
+
+ self.stepCtrl.SetValue(str(self.__CalcStepping(min, max, ngroups)))
+
+ self.parent.AllowGenerate(self.GetStepping() is not None)
+ else:
+ self.parent.AllowGenerate(False)
+
+
+ def _OnSteppingChanged(self, event):
+ if self.numGroupsChanging:
+ self.numGroupsChanging = False
+ return
+
+ step = self.GetStepping()
+ min = self.GetMin()
+ max = self.GetMax()
+
+ if step is not None \
+ and min is not None \
+ and max is not None \
+ and step != 0:
+
+ #
+ # see note in _OnNumGroupsChanged
+ #
+ self.steppingChanging = True
+ self.numGroupsCtrl.SetValue(self.__CalcNumGroups(min, max, step))
+
+ self.parent.AllowGenerate(self.GetNumGroups() is not None)
+ else:
+ self.parent.AllowGenerate(False)
+
+ def _OnRetrieve(self, event):
+ table = self.layer.ShapeStore().Table()
+ if table is not None:
+ ThubanBeginBusyCursor()
+ try:
+ min, max = table.ValueRange(self.fieldName)
+ self.minCtrl.SetValue(str(min))
+ self.maxCtrl.SetValue(str(max))
+ finally:
+ ThubanEndBusyCursor()
+
+ def __GetValidatedTypeEntry(self, win, value, type, badValue = None):
+
+ if type == FIELDTYPE_INT:
+ func = int
+ elif type == FIELDTYPE_DOUBLE:
+ func = float
+ elif type == FIELDTYPE_STRING:
+ func = str
+ else:
+ assert False, "Unsupported FIELDTYPE"
+ pass
+
+ if self.__ValidateEntry(win, value, func, badValue):
+ return func(value)
+
+ return None
+
+ def __ValidateEntry(self, win, value, test, badValue = None):
+
+ valid = value != ""
+
+ try:
+ if valid:
+ value = test(value)
+
+ if badValue is not None:
+ valid = value != test(badValue)
+ except ValueError:
+ valid = False
+
+ if valid:
+ win.SetForegroundColour(wx.BLACK)
+ else:
+ win.SetForegroundColour(wx.RED)
+
+ win.Refresh()
+
+ return valid
+
+ def __CalcStepping(self, min, max, ngroups):
+ if self.fieldType == FIELDTYPE_INT:
+ step = int((max - min + 1) / float(ngroups))
+ else:
+ step = (max - min) / float(ngroups)
+
+ return step
+
+ def __CalcNumGroups(self, min, max, step):
+ n = int((max - min) / step)
+ if n == 0:
+ n = 1
+
+ if self.fieldType == FIELDTYPE_INT and step == 1:
+ n += 1
+
+ return n
+
+
+ID_UNIQUE_RETRIEVE = 4001
+ID_UNIQUE_USEALL = 4002
+ID_UNIQUE_USE = 4003
+ID_UNIQUE_DONTUSE = 4004
+ID_UNIQUE_USENONE = 4005
+ID_UNIQUE_SORTAVAIL = 4006
+ID_UNIQUE_SORTUSE = 4007
+ID_UNIQUE_REVAVAIL = 4008
+ID_UNIQUE_REVUSE = 4009
+
+class GenUniquePanel(wx.Panel):
+
+ def __init__(self, parent, layer, fieldName, fieldType):
+ wx.Panel.__init__(self, parent, -1)
+
+ self.parent = parent
+ self.layer = layer
+ self.fieldName = fieldName
+ self.fieldType = fieldType
+
+ topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
+ wx.VERTICAL)
+
+
+ #bsizer = wxBoxSizer(wxVERTICAL)
+ topSizer.Add(wx.Button(self, ID_UNIQUE_RETRIEVE,
+ _("Retrieve From Table")),
+ 0, wx.ALL | wx.ALIGN_RIGHT, 4)
+
+ self.Bind(wx.EVT_BUTTON, self._OnRetrieve, id=ID_UNIQUE_RETRIEVE)
+
+ #topSizer.Add(bsizer, 0, wx.ALL, 4)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ self.dataList = []
+
+ psizer = wx.BoxSizer(wx.VERTICAL)
+ self.list_avail = wx.ListCtrl(self, -1,
+ style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
+ self.list_avail.InsertColumn(0, _("Available"))
+ self.list_avail_data = []
+ psizer.Add(self.list_avail, 1, wx.GROW, 0)
+
+ bsizer = wx.BoxSizer(wx.HORIZONTAL)
+ bsizer.Add(wx.Button(self, ID_UNIQUE_SORTAVAIL, _("Sort")))
+ self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTAVAIL)
+
+ bsizer.Add(wx.Button(self, ID_UNIQUE_REVAVAIL, _("Reverse")))
+ self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVAVAIL)
+
+ psizer.Add(bsizer, 0, wx.GROW, 0)
+ sizer.Add(psizer, 1, wx.GROW, 0)
+
+
+ bsizer = wx.BoxSizer(wx.VERTICAL)
+
+ bmp = resource.GetBitmapResource(USEALL_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USEALL, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+ bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USE, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+ bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_DONTUSE, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+ bmp = resource.GetBitmapResource(USENONE_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer.Add(wx.BitmapButton(self, ID_UNIQUE_USENONE, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+
+ self.Bind(wx.EVT_BUTTON, self._OnUseAll, id=ID_UNIQUE_USEALL)
+ self.Bind(wx.EVT_BUTTON, self._OnUse, id=ID_UNIQUE_USE)
+ self.Bind(wx.EVT_BUTTON, self._OnDontUse, id=ID_UNIQUE_DONTUSE)
+ self.Bind(wx.EVT_BUTTON, self._OnUseNone, id=ID_UNIQUE_USENONE)
+
+ sizer.Add(bsizer, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
+
+ psizer = wx.BoxSizer(wx.VERTICAL)
+ self.list_use = wx.ListCtrl(self, -1,
+ style=wx.LC_REPORT | wx.LC_SINGLE_SEL)
+ self.list_use.InsertColumn(0, _("Use"))
+ self.list_use_data = []
+ psizer.Add(self.list_use, 1, wx.GROW, 0)
+
+ bsizer = wx.BoxSizer(wx.HORIZONTAL)
+ bsizer.Add(wx.Button(self, ID_UNIQUE_SORTUSE, _("Sort")))
+ self.Bind(wx.EVT_BUTTON, self._OnSortList, id=ID_UNIQUE_SORTUSE)
+
+ bsizer.Add(wx.Button(self, ID_UNIQUE_REVUSE, _("Reverse")))
+ self.Bind(wx.EVT_BUTTON, self._OnReverseList, id=ID_UNIQUE_REVUSE)
+
+ psizer.Add(bsizer, 0, wx.GROW, 0)
+
+ sizer.Add(psizer, 1, wx.GROW, 0)
+
+
+ topSizer.Add(sizer, 1, wx.GROW, 0)
+
+ self.SetSizer(topSizer)
+ self.SetAutoLayout(True)
+ topSizer.SetSizeHints(self)
+
+ width, height = self.list_avail.GetSizeTuple()
+ self.list_avail.SetColumnWidth(0,width)
+ width, height = self.list_use.GetSizeTuple()
+ self.list_use.SetColumnWidth(0,width)
+
+ self.parent.AllowGenerate(False)
+
+ def GetNumGroups(self):
+ return self.list_use.GetItemCount()
+
+ def GetValueList(self):
+ list = []
+ for i in range(self.list_use.GetItemCount()):
+ list.append(self.dataList[self.list_use.GetItemData(i)])
+ return list
+
+ def _OnSortList(self, event):
+ id = event.GetId()
+
+ if id == ID_UNIQUE_SORTUSE:
+ list = self.list_use
+ else:
+ list = self.list_avail
+
+ list.SortItems(lambda i1, i2: cmp(self.dataList[i1],
+ self.dataList[i2]))
+
+ def _OnReverseList(self, event):
+ id = event.GetId()
+
+ if id == ID_UNIQUE_REVUSE:
+ list = self.list_use
+ else:
+ list = self.list_avail
+
+ #
+ # always returning 1 reverses the list
+ #
+ list.SortItems(lambda i1, i2: 1)
+
+ def _OnRetrieve(self, event):
+ self.list_use.DeleteAllItems()
+ self.list_use_data = []
+ self.list_avail.DeleteAllItems()
+ self.list_avail_data = []
+
+ ThubanBeginBusyCursor()
+ try:
+ list = self.layer.ShapeStore().Table().UniqueValues(self.fieldName)
+ index = 0
+ for v in list:
+ self.dataList.append(v)
+ i = self.list_avail.InsertStringItem(index, str(v))
+ self.list_avail.SetItemData(index, i)
+
+ self.list_avail_data.append(v)
+ index += 1
+ finally:
+ ThubanEndBusyCursor()
+
+ def _OnUseAll(self, event):
+ for i in range(self.list_avail.GetItemCount()):
+ self.__MoveListItem(0, self.list_avail, self.list_use)
+
+ def _OnUse(self, event):
+ self.__MoveSelectedItems(self.list_avail, self.list_use)
+
+ def _OnDontUse(self, event):
+ self.__MoveSelectedItems(self.list_use, self.list_avail)
+
+ def _OnUseNone(self, event):
+
+ for i in range(self.list_use.GetItemCount()):
+ self.__MoveListItem(0, self.list_use, self.list_avail)
+
+ def __MoveSelectedItems(self, list_src, list_dest):
+ while True:
+ index = list_src.GetNextItem(-1,
+ wx.LIST_NEXT_ALL,
+ wx.LIST_STATE_SELECTED)
+
+ if index == -1:
+ break
+
+ self.__MoveListItem(index, list_src, list_dest)
+
+
+ def __MoveListItem(self, index, list_src, list_dest):
+
+ item = list_src.GetItem(index)
+
+ x = list_dest.InsertStringItem(
+ list_dest.GetItemCount(),
+ str(self.dataList[item.GetData()]))
+
+ list_dest.SetItemData(x, item.GetData())
+
+ list_src.DeleteItem(index)
+
+# def _OnListSize(self, event):
+# list = event.GetEventObject()
+
+# list.SetColumnWidth(0, event.GetSize().GetWidth())
+#
+
+ID_QUANTILES_RANGE = 4001
+ID_QUANTILES_RETRIEVE = 4002
+
+class GenQuantilesPanel(wx.Panel):
+
+ def __init__(self, parent, layer, fieldName, fieldType):
+ wx.Panel.__init__(self, parent, -1)
+
+ self.parent = parent
+ self.layer = layer
+ self.fieldName = fieldName
+ self.fieldType = fieldType
+
+ topBox = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""),
+ wx.VERTICAL)
+
+ self.text_range = wx.TextCtrl(self, ID_QUANTILES_RANGE, "")
+ self.button_retrieve = wx.Button(self, ID_QUANTILES_RETRIEVE,
+ _("Retrieve from Table"))
+
+ self.spin_numClasses = wx.SpinCtrl(self, -1, style=wx.TE_RIGHT)
+ self.spin_numClasses.SetRange(2, sys.maxint)
+ self.spin_numClasses.SetValue(2)
+
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(wx.StaticText(self, -1, _("Apply to Range")), 0, wx.ALL, 4)
+ sizer.Add(self.text_range, 1, wx.ALL, 4)
+ sizer.Add(self.button_retrieve, 0, wx.ALL, 4)
+
+ topBox.Add(sizer, 0, wx.EXPAND, 0)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(wx.StaticText(self, -1, _("Number of Classes:")), 0, wx.ALL, 4)
+ sizer.Add(self.spin_numClasses, 1, wx.ALL, 4)
+
+ topBox.Add(sizer, 0, wx.EXPAND, 0)
+
+ self.SetSizer(topBox)
+ self.SetAutoLayout(True)
+ topBox.Fit(self)
+ topBox.SetSizeHints(self)
+
+ self.Bind(wx.EVT_TEXT, self.OnRangeText, id=ID_QUANTILES_RANGE)
+ self.Bind(wx.EVT_BUTTON, self.OnRetrieve, id=ID_QUANTILES_RETRIEVE)
+
+ self.__range = None
+
+ def GetNumGroups(self):
+ return self.spin_numClasses.GetValue()
+
+ def GetRange(self):
+ assert self.__range is not None
+
+ return self.__range
+
+ def GetList(self):
+ _list = []
+ table = self.layer.ShapeStore().Table()
+ if table is not None:
+ ThubanBeginBusyCursor()
+ try:
+ #
+ # FIXME: Replace with a call to table when the method
+ # has been written to get all the values
+ #
+ for i in range(table.NumRows()):
+ _list.append(table.ReadValue(i, self.fieldName,
+ row_is_ordinal = True))
+ finally:
+ ThubanEndBusyCursor()
+
+ return _list
+
+ def OnRangeText(self, event):
+
+ try:
+ self.__range = Range(self.text_range.GetValue())
+ except ValueError:
+ self.__range = None
+
+ if self.__range is not None:
+ self.text_range.SetForegroundColour(wx.BLACK)
+ else:
+ self.text_range.SetForegroundColour(wx.RED)
+
+ def OnRetrieve(self, event):
+ table = self.layer.ShapeStore().Table()
+ if table is not None:
+ ThubanBeginBusyCursor()
+ try:
+ min, max = table.ValueRange(self.fieldName)
+ self.text_range.SetValue("[" + str(min) + ";" + str(max) + "]")
+ # This is a workaround, which will result in OnRangeText
+ # being called twice on some platforms.
+ # Testing showed this is needed with current wx 2.4. versions
+ # on MacOSX to guarantee that it is called at all.
+ self.OnRangeText(None)
+ finally:
+ ThubanEndBusyCursor()
+
+ID_CUSTOMRAMP_COPYSTART = 4001
+ID_CUSTOMRAMP_COPYEND = 4002
+ID_CUSTOMRAMP_EDITSTART = 4003
+ID_CUSTOMRAMP_EDITEND = 4004
+ID_CUSTOMRAMP_SPROP = 4005
+ID_CUSTOMRAMP_EPROP = 4006
+
+class CustomRampPanel(wx.Panel):
+
+ def __init__(self, parent, shapeType):
+ wx.Panel.__init__(self, parent, -1)
+
+ topSizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, ""), wx.HORIZONTAL)
+
+ bsizer = wx.BoxSizer(wx.VERTICAL)
+ bsizer.Add(wx.StaticText(self, -1, _("Start:")), 0, wx.ALL | wx.CENTER, 4)
+ self.startPropCtrl = classifier.ClassGroupPropertiesCtrl(
+ self, ID_CUSTOMRAMP_SPROP,
+ ClassGroupProperties(), shapeType,
+ style=wx.SIMPLE_BORDER, size=(40, 20))
+ bsizer.Add(self.startPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
+ bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITSTART, _("Change")),
+ 0, wx.GROW | wx.ALL | wx.CENTER, 4)
+
+ topSizer.Add(bsizer,
+ 1, wx.ALL \
+ | wx.SHAPED \
+ | wx.ALIGN_CENTER_HORIZONTAL \
+ | wx.ALIGN_CENTER_VERTICAL, \
+ 4)
+
+ bmp = resource.GetBitmapResource(USE_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer = wx.BoxSizer(wx.VERTICAL)
+ bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYSTART, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+ bmp = resource.GetBitmapResource(USENOT_BMP, wx.BITMAP_TYPE_XPM)
+ bsizer.Add(wx.BitmapButton(self, ID_CUSTOMRAMP_COPYEND, bmp),
+ 0, wx.GROW | wx.ALL, 4)
+
+ topSizer.Add(bsizer,
+ 0, wx.ALL \
+ | wx.ALIGN_CENTER_HORIZONTAL \
+ | wx.ALIGN_CENTER_VERTICAL,
+ 4)
+
+ bsizer = wx.BoxSizer(wx.VERTICAL)
+ bsizer.Add(wx.StaticText(self, -1, _("End:")), 0, wx.ALL | wx.CENTER, 4)
+ self.endPropCtrl = classifier.ClassGroupPropertiesCtrl(
+ self, ID_CUSTOMRAMP_EPROP,
+ ClassGroupProperties(), shapeType,
+ style=wx.SIMPLE_BORDER, size=(40, 20))
+ bsizer.Add(self.endPropCtrl, 1, wx.GROW | wx.ALL | wx.CENTER, 4)
+ bsizer.Add(wx.Button(self, ID_CUSTOMRAMP_EDITEND, _("Change")),
+ 0, wx.GROW | wx.ALL | wx.CENTER, 4)
+
+ topSizer.Add(bsizer,
+ 1, wx.ALL \
+ | wx.SHAPED \
+ | wx.ALIGN_RIGHT \
+ | wx.ALIGN_CENTER_HORIZONTAL \
+ | wx.ALIGN_CENTER_VERTICAL,
+ 4)
+
+ self.Bind(wx.EVT_BUTTON, self._OnCopyStart, id=ID_CUSTOMRAMP_COPYSTART)
+ self.Bind(wx.EVT_BUTTON, self._OnCopyEnd, id=ID_CUSTOMRAMP_COPYEND)
+ self.Bind(wx.EVT_BUTTON, self._OnEditStart, id=ID_CUSTOMRAMP_EDITSTART)
+ self.Bind(wx.EVT_BUTTON, self._OnEditEnd, id=ID_CUSTOMRAMP_EDITEND)
+
+ self.SetSizer(topSizer)
+ self.SetAutoLayout(True)
+ topSizer.SetSizeHints(self)
+
+ def GetRamp(self):
+ return CustomRamp(self.startPropCtrl.GetProperties(),
+ self.endPropCtrl.GetProperties())
+
+ def _OnCopyStart(self, event):
+ self.endPropCtrl.SetProperties(self.startPropCtrl.GetProperties())
+
+ def _OnCopyEnd(self, event):
+ self.startPropCtrl.SetProperties(self.endPropCtrl.GetProperties())
+
+ def _OnEditStart(self, event):
+ self.startPropCtrl.DoEdit()
+
+ def _OnEditEnd(self, event):
+ self.endPropCtrl.DoEdit()
+
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/classifier.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/classifier.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/classifier.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1550 @@
+# Copyright (c) 2003-2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2003-2004)
+# Martin Schulze <joey at infodrom.org> (2004)
+# Frank Koormann <frank at intevation.de> (2003, 2006)
+# Bernhard Herzog <bh at intevation.de> (2003)
+# Jonathan Coles <jonathan at intevation.de> (2003)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Dialog for classifying how layers are displayed"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: classifier.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import copy
+import re
+
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
+ FIELDTYPE_STRING
+
+import wx
+from wx import grid
+
+from Thuban import _
+from Thuban.UI.common import Color2wxColour, wxColour2Color
+
+from Thuban.Model.messages import MAP_LAYERS_REMOVED, LAYER_SHAPESTORE_REPLACED
+from Thuban.Model.range import Range
+from Thuban.Model.classification import \
+ Classification, ClassGroupDefault, \
+ ClassGroupSingleton, ClassGroupPattern, ClassGroupRange, ClassGroupMap, \
+ ClassGroupProperties
+
+from Thuban.Model.color import Transparent
+
+from Thuban.Model.layer import Layer
+from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
+
+from Thuban.UI.classgen import ClassGenDialog
+from Thuban.UI.colordialog import ColorDialog
+
+from Thuban.UI.layerproperties import LayerProperties
+from messages import MAP_REPLACED
+
+
+# table columns
+COL_VISIBLE = 0
+COL_SYMBOL = 1
+COL_VALUE = 2
+COL_LABEL = 3
+NUM_COLS = 4
+
+# indices into the client data lists in Classifier.fields
+FIELD_CLASS = 0
+FIELD_TYPE = 1
+FIELD_NAME = 2
+
+#
+# this is a silly work around to ensure that the table that is
+# passed into SetTable is the same that is returned by GetTable
+#
+import weakref
+class ClassGrid(grid.Grid):
+
+
+ def __init__(self, parent, classifier):
+ """Constructor.
+
+ parent -- the parent window
+
+ clazz -- the working classification that this grid should
+ use for display.
+ """
+ grid.Grid.__init__(self, parent, -1, style = 0)
+
+ self.classifier = classifier
+
+ self.currentSelection = []
+
+ self.Bind(grid.EVT_GRID_CELL_LEFT_DCLICK, self._OnCellDClick)
+ self.Bind(grid.EVT_GRID_RANGE_SELECT, self._OnSelectedRange)
+ self.Bind(grid.EVT_GRID_SELECT_CELL, self._OnSelectedCell)
+ self.Bind(grid.EVT_GRID_COL_SIZE, self._OnCellResize)
+ self.Bind(grid.EVT_GRID_ROW_SIZE, self._OnCellResize)
+ self.Bind(grid.EVT_GRID_LABEL_RIGHT_CLICK, self._OnLabelRightClicked)
+
+
+ #def GetCellAttr(self, row, col):
+ #print "GetCellAttr ", row, col
+ #Grid.GetCellAttr(self, row, col)
+
+ def CreateTable(self, clazz, fieldType, shapeType, group = None):
+
+ assert isinstance(clazz, Classification)
+
+ table = self.GetTable()
+ if table is None:
+ w = self.GetDefaultColSize() * NUM_COLS \
+ + self.GetDefaultRowLabelSize()
+ h = self.GetDefaultRowSize() * 4 \
+ + self.GetDefaultColLabelSize()
+
+ self.SetDimensions(-1, -1, w, h)
+ self.SetSizeHints(w, h, -1, -1)
+ table = ClassTable(self)
+ self.SetTable(table, True)
+
+
+ self.SetSelectionMode(grid.Grid.wxGridSelectRows)
+ self.ClearSelection()
+
+ table.Reset(clazz, fieldType, shapeType, group)
+
+ def GetCurrentSelection(self):
+ """Return the currently highlighted rows as an increasing list
+ of row numbers."""
+ sel = copy.copy(self.currentSelection)
+ sel.sort()
+ return sel
+
+ def GetSelectedRows(self):
+ return self.GetCurrentSelection()
+
+ #def SetCellRenderer(self, row, col, renderer):
+ #raise ValueError(_("Must not allow setting of renderer in ClassGrid!"))
+
+ #
+ # [Set|Get]Table is taken from http://wiki.wxpython.org
+ # they are needed as a work around to ensure that the table
+ # that is passed to SetTable is the one that is returned
+ # by GetTable.
+ #
+ def SetTable(self, object, *attributes):
+ self.tableRef = weakref.ref(object)
+ return grid.Grid.SetTable(self, object, *attributes)
+
+ def GetTable(self):
+ try:
+ return self.tableRef()
+ except:
+ return None
+
+ def DeleteSelectedRows(self):
+ """Deletes all highlighted rows.
+
+ If only one row is highlighted then after it is deleted the
+ row that was below the deleted row is highlighted."""
+
+ sel = self.GetCurrentSelection()
+
+ # nothing to do
+ if len(sel) == 0: return
+
+ # if only one thing is selected check if it is the default
+ # data row, because we can't remove that
+ if len(sel) == 1:
+ #group = self.GetTable().GetValueAsCustom(sel[0], COL_SYMBOL, None)
+ group = self.GetTable().GetClassGroup(sel[0])
+ if isinstance(group, ClassGroupDefault):
+ wx.MessageDialog(self,
+ _("The Default group cannot be removed."),
+ style = wx.OK | wx.ICON_EXCLAMATION).ShowModal()
+ return
+
+
+ self.ClearSelection()
+
+ # we need to remove things from the bottom up so we don't
+ # change the indexes of rows that will be deleted next
+ sel.reverse()
+
+ #
+ # actually remove the rows
+ #
+ table = self.GetTable()
+ for row in sel:
+ table.DeleteRows(row)
+
+ #
+ # if there was only one row selected highlight the row
+ # that was directly below it, or move up one if the
+ # deleted row was the last row.
+ #
+ if len(sel) == 1:
+ r = sel[0]
+ if r > self.GetNumberRows() - 1:
+ r = self.GetNumberRows() - 1
+ self.SelectRow(r)
+
+
+ def SelectGroup(self, group, makeVisible = True):
+ if group is None: return
+
+ assert isinstance(group, ClassGroup)
+
+ table = self.GetTable()
+
+ assert table is not None
+
+ for i in range(table.GetNumberRows()):
+ g = table.GetClassGroup(i)
+ if g is group:
+ self.SelectRow(i)
+ if makeVisible:
+ self.MakeCellVisible(i, 0)
+ break
+
+#
+# XXX: This isn't working, and there is no way to deselect rows wxPython!
+#
+# def DeselectRow(self, row):
+# self.ProcessEvent(
+# GridRangeSelectEvent(-1,
+# wxEVT_GRID_RANGE_SELECT,
+# self,
+# (row, row), (row, row),
+# sel = False))
+
+ def _OnCellDClick(self, event):
+ """Handle a double click on a cell."""
+
+ r = event.GetRow()
+ c = event.GetCol()
+
+ if c == COL_SYMBOL:
+ self.classifier.EditSymbol(r)
+ else:
+ event.Skip()
+
+ #
+ # _OnSelectedRange() and _OnSelectedCell() were borrowed
+ # from http://wiki.wxpython.org to keep track of which
+ # cells are currently highlighted
+ #
+ def _OnSelectedRange(self, event):
+ """Internal update to the selection tracking list"""
+ if event.Selecting():
+ for index in range( event.GetTopRow(), event.GetBottomRow()+1):
+ if index not in self.currentSelection:
+ self.currentSelection.append( index )
+ else:
+ for index in range( event.GetTopRow(), event.GetBottomRow()+1):
+ while index in self.currentSelection:
+ self.currentSelection.remove( index )
+ #self.ConfigureForSelection()
+
+ event.Skip()
+
+ def _OnSelectedCell( self, event ):
+ """Internal update to the selection tracking list"""
+ self.currentSelection = [ event.GetRow() ]
+ #self.ConfigureForSelection()
+ event.Skip()
+
+ def _OnCellResize(self, event):
+ self.FitInside()
+ event.Skip()
+
+ def _OnLabelRightClicked(self, event):
+ """Process right click on label, raise popup for row labels."""
+ row, col = event.GetRow(), event.GetCol()
+ if col == -1:
+ self.labelPopup(event, row)
+
+ def labelPopup(self, event, row):
+ """Raise grid label popup."""
+ # check if row label is Pattern or Singleton
+ label = self.GetRowLabelValue(row)
+ if (label == _("Pattern") or label == _("Singleton")):
+ xe,ye = event.GetPosition()
+ x=self.GetRowSize(row)/2
+ menu = wx.Menu()
+ patternID = wx.NewId()
+ singletonID = wx.NewId()
+
+ def _SetSingleton(event, self=self, row=row):
+ table = self.GetTable()
+ group = table.clazz.GetGroup(row - 1)
+ if not isinstance(group, ClassGroupSingleton):
+ ngroup = ClassGroupSingleton(
+ group.GetPattern(),
+ group.GetProperties(),
+ group.GetLabel()
+ )
+ table.SetClassGroup(row, ngroup)
+
+ def _SetPattern(event, self=self, row=row):
+ table = self.GetTable()
+ group = table.clazz.GetGroup(row - 1)
+ if not isinstance(group, ClassGroupPattern):
+ try:
+ re.compile(group.GetValue())
+ except:
+ pass
+ else:
+ ngroup = ClassGroupPattern(
+ group.GetValue(),
+ group.GetProperties(),
+ group.GetLabel()
+ )
+ table.SetClassGroup(row, ngroup)
+
+ menu.Append(singletonID, _("Singleton"))
+ self.Bind(wx.EVT_MENU, _SetSingleton, id=singletonID)
+ if self.GetTable().fieldType == FIELDTYPE_STRING:
+ menu.Append(patternID, _("Pattern"))
+ self.Bind(wx.EVT_MENU, _SetPattern, id=patternID)
+ self.PopupMenu(menu, wx.Point(x,ye))
+ menu.Destroy()
+
+class ClassTable(grid.PyGridTableBase):
+ """Represents the underlying data structure for the grid."""
+
+ __col_labels = [_("Visible"), _("Symbol"), _("Value"), _("Label")]
+
+
+ def __init__(self, view = None):
+ """Constructor.
+
+ shapeType -- the type of shape that the layer uses
+
+ view -- a Grid object that uses this class for its table
+ """
+
+ grid.PyGridTableBase.__init__(self)
+
+ assert len(ClassTable.__col_labels) == NUM_COLS
+
+ self.clazz = None
+ self.__colAttr = {}
+
+ self.SetView(view)
+
+ def Reset(self, clazz, fieldType, shapeType, group = None):
+ """Reset the table with the given data.
+
+ This is necessary because wxWindows does not allow a grid's
+ table to change once it has been intially set and so we
+ need a way of modifying the data.
+
+ clazz -- the working classification that this table should
+ use for display. This may be different from the
+ classification in the layer.
+
+ shapeType -- the type of shape that the layer uses
+ """
+
+ assert isinstance(clazz, Classification)
+
+ self.GetView().BeginBatch()
+
+ self.fieldType = fieldType
+ self.shapeType = shapeType
+
+ self.SetClassification(clazz, group)
+ self.__Modified(-1)
+
+ self.__colAttr = {}
+
+ attr = grid.GridCellAttr()
+ attr.SetEditor(grid.GridCellBoolEditor())
+ attr.SetRenderer(grid.GridCellBoolRenderer())
+ attr.SetAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
+ self.__colAttr[COL_VISIBLE] = attr
+
+ attr = grid.GridCellAttr()
+ attr.SetRenderer(ClassRenderer(self.shapeType))
+ attr.SetReadOnly()
+ self.__colAttr[COL_SYMBOL] = attr
+
+ self.GetView().EndBatch()
+ self.GetView().FitInside()
+
+ def GetClassification(self):
+ """Return the current classification."""
+ return self.clazz
+
+ def SetClassification(self, clazz, group = None):
+ """Fill in the table with the given classification.
+ Select the given group if group is not None.
+ """
+
+ self.GetView().BeginBatch()
+
+ old_len = self.GetNumberRows()
+
+ row = -1
+ self.clazz = clazz
+
+ self.__NotifyRowChanges(old_len, self.GetNumberRows())
+
+ #
+ # XXX: this is dead code at the moment
+ #
+ if row > -1:
+ self.GetView().ClearSelection()
+ self.GetView().SelectRow(row)
+ self.GetView().MakeCellVisible(row, 0)
+
+ self.__Modified()
+
+ self.GetView().EndBatch()
+ self.GetView().FitInside()
+
+ def __NotifyRowChanges(self, curRows, newRows):
+ """Make sure table updates correctly if the number of
+ rows changes.
+ """
+ #
+ # silly message processing for updates to the number of
+ # rows and columns
+ #
+ if newRows > curRows:
+ msg = grid.GridTableMessage(self,
+ grid.GRIDTABLE_NOTIFY_ROWS_APPENDED,
+ newRows - curRows) # how many
+ self.GetView().ProcessTableMessage(msg)
+ self.GetView().FitInside()
+ elif newRows < curRows:
+ msg = grid.GridTableMessage(self,
+ grid.GRIDTABLE_NOTIFY_ROWS_DELETED,
+ curRows, # position
+ curRows - newRows) # how many
+ self.GetView().ProcessTableMessage(msg)
+ self.GetView().FitInside()
+
+ def __SetRow(self, row, group):
+ """Set a row's data to that of the group.
+
+ The table is considered modified after this operation.
+
+ row -- if row is < 0 'group' is inserted at the top of the table
+ if row is >= GetNumberRows() or None 'group' is append to
+ the end of the table.
+ otherwise 'group' replaces row 'row'
+ """
+
+ # either append or replace
+ if row is None or row >= self.GetNumberRows():
+ self.clazz.AppendGroup(group)
+ elif row < 0:
+ self.clazz.InsertGroup(0, group)
+ else:
+ if row == 0:
+ self.clazz.SetDefaultGroup(group)
+ else:
+ self.clazz.ReplaceGroup(row - 1, group)
+
+ self.__Modified()
+
+ def GetColLabelValue(self, col):
+ """Return the label for the given column."""
+ return self.__col_labels[col]
+
+ def GetRowLabelValue(self, row):
+ """Return the label for the given row."""
+
+ if row == 0:
+ return _("Default")
+ else:
+ group = self.clazz.GetGroup(row - 1)
+ if isinstance(group, ClassGroupDefault): return _("Default")
+ if isinstance(group, ClassGroupSingleton): return _("Singleton")
+ if isinstance(group, ClassGroupPattern): return _("Pattern")
+ if isinstance(group, ClassGroupRange): return _("Range")
+ if isinstance(group, ClassGroupMap): return _("Map")
+
+ assert False # shouldn't get here
+ return ""
+
+ def GetNumberRows(self):
+ """Return the number of rows."""
+ if self.clazz is None:
+ return 0
+
+ return self.clazz.GetNumGroups() + 1 # +1 for default group
+
+ def GetNumberCols(self):
+ """Return the number of columns."""
+ return NUM_COLS
+
+ def IsEmptyCell(self, row, col):
+ """Determine if a cell is empty. This is always false."""
+ return False
+
+ def GetValue(self, row, col):
+ """Return the object that is used to represent the given
+ cell coordinates. This may not be a string."""
+ return self.GetValueAsCustom(row, col, None)
+
+ def SetValue(self, row, col, value):
+ """Assign 'value' to the cell specified by 'row' and 'col'.
+
+ The table is considered modified after this operation.
+ """
+
+ self.SetValueAsCustom(row, col, None, value)
+
+ def GetValueAsCustom(self, row, col, typeName):
+ """Return the object that is used to represent the given
+ cell coordinates. This may not be a string.
+
+ typeName -- unused, but needed to overload wxPyGridTableBase
+ """
+
+ if row == 0:
+ group = self.clazz.GetDefaultGroup()
+ else:
+ group = self.clazz.GetGroup(row - 1)
+
+
+ if col == COL_VISIBLE:
+ return group.IsVisible()
+
+ if col == COL_SYMBOL:
+ return group.GetProperties()
+
+ if col == COL_LABEL:
+ return group.GetLabel()
+
+ # col must be COL_VALUE
+ assert col == COL_VALUE
+
+ if isinstance(group, ClassGroupDefault):
+ return _("DEFAULT")
+ elif isinstance(group, ClassGroupSingleton):
+ return group.GetValue()
+ elif isinstance(group, ClassGroupPattern):
+ return group.GetPattern()
+ elif isinstance(group, ClassGroupRange):
+ return group.GetRange()
+
+ assert False # shouldn't get here
+ return None
+
+ def __ParseInput(self, value):
+ """Try to determine what kind of input value is
+ (string, number, or range)
+
+ Returns a tuple (type, data) where type is 0 if data is
+ a singleton value, 1 if is a range or 2 if it is a pattern.
+ """
+
+ type = self.fieldType
+
+ if type == FIELDTYPE_STRING:
+ # Approach: if we can compile the value as an expression,
+ # make it a pattern, else a singleton.
+ # This is quite crude, however I don't have a better idea:
+ # How to distinct the singleton "Thuban" from the pattern "Thuban"?
+ try:
+ re.compile(value)
+ except:
+ return (0, value)
+ else:
+ return (2, value)
+ elif type in (FIELDTYPE_INT, FIELDTYPE_DOUBLE):
+ if type == FIELDTYPE_INT:
+ # the float call allows the user to enter 1.0 for 1
+ conv = lambda p: int(float(p))
+ else:
+ conv = float
+
+ #
+ # first try to take the input as a single number
+ # if there's an exception try to break it into
+ # a range. if there is an exception here, let it
+ # pass up to the calling function.
+ #
+ try:
+ return (0, conv(value))
+ except ValueError:
+ return (1, Range(value))
+
+ assert False # shouldn't get here
+ return (0,None)
+
+ def SetValueAsCustom(self, row, col, typeName, value):
+ """Set the cell specified by 'row' and 'col' to 'value'.
+
+ If column represents the value column, the input is parsed
+ to determine if a string, number, or range was entered.
+ A new ClassGroup may be created if the type of data changes.
+
+ The table is considered modified after this operation.
+
+ typeName -- unused, but needed to overload wxPyGridTableBase
+ """
+
+ assert 0 <= col < self.GetNumberCols()
+ assert 0 <= row < self.GetNumberRows()
+
+ if row == 0:
+ group = self.clazz.GetDefaultGroup()
+ else:
+ group = self.clazz.GetGroup(row - 1)
+
+ mod = True # assume the data will change
+
+ if col == COL_VISIBLE:
+ group.SetVisible(value)
+ elif col == COL_SYMBOL:
+ group.SetProperties(value)
+ elif col == COL_LABEL:
+ group.SetLabel(value)
+ elif col == COL_VALUE:
+ if isinstance(group, ClassGroupDefault):
+ # not allowed to modify the default value
+ pass
+ elif isinstance(group, ClassGroupMap):
+ # something special
+ pass
+ else: # SINGLETON, RANGE
+ try:
+ dataInfo = self.__ParseInput(value)
+ except ValueError:
+ # bad input, ignore the request
+ mod = False
+ else:
+
+ changed = False
+ ngroup = group
+ props = group.GetProperties()
+
+ #
+ # try to update the values, which may include
+ # changing the underlying group type if the
+ # group was a singleton and a range was entered
+ #
+ if dataInfo[0] == 0:
+ if not isinstance(group, ClassGroupSingleton):
+ ngroup = ClassGroupSingleton(props = props)
+ changed = True
+ ngroup.SetValue(dataInfo[1])
+ elif dataInfo[0] == 1:
+ if not isinstance(group, ClassGroupRange):
+ ngroup = ClassGroupRange(props = props)
+ changed = True
+ ngroup.SetRange(dataInfo[1])
+ elif dataInfo[0] == 2:
+ if not isinstance(group, ClassGroupPattern):
+ ngroup = ClassGroupPattern(props = props)
+ changed = True
+ ngroup.SetPattern(dataInfo[1])
+ else:
+ assert False
+ pass
+
+ if changed:
+ ngroup.SetLabel(group.GetLabel())
+ self.SetClassGroup(row, ngroup)
+ else:
+ assert False # shouldn't be here
+ pass
+
+ if mod:
+ self.__Modified()
+ self.GetView().Refresh()
+
+ def GetAttr(self, row, col, someExtraParameter):
+ """Returns the cell attributes"""
+
+ return self.__colAttr.get(col, grid.GridCellAttr()).Clone()
+
+ def GetClassGroup(self, row):
+ """Return the ClassGroup object representing row 'row'."""
+
+ #return self.GetValueAsCustom(row, COL_SYMBOL, None)
+ if row == 0:
+ return self.clazz.GetDefaultGroup()
+ else:
+ return self.clazz.GetGroup(row - 1)
+
+ def SetClassGroup(self, row, group):
+ """Set the given row to properties of group."""
+ self.__SetRow(row, group)
+ self.GetView().Refresh()
+
+ def __Modified(self, mod = True):
+ """Adjust the modified flag.
+
+ mod -- if -1 set the modified flag to False, otherwise perform
+ an 'or' operation with the current value of the flag and
+ 'mod'
+ """
+
+ if mod == -1:
+ self.modified = False
+ else:
+ self.modified = mod or self.modified
+
+ def IsModified(self):
+ """True if this table is considered modified."""
+ return self.modified
+
+ def DeleteRows(self, pos, numRows = 1):
+ """Deletes 'numRows' beginning at row 'pos'.
+
+ The row representing the default group is not removed.
+
+ The table is considered modified if any rows are removed.
+ """
+
+ assert pos >= 0
+ old_len = self.GetNumberRows()
+ for row in range(pos, pos - numRows, -1):
+ group = self.GetClassGroup(row)
+ if row != 0:
+ self.clazz.RemoveGroup(row - 1)
+ self.__Modified()
+
+ if self.IsModified():
+ self.__NotifyRowChanges(old_len, self.GetNumberRows())
+
+ def AppendRows(self, numRows = 1):
+ """Append 'numRows' empty rows to the end of the table.
+
+ The table is considered modified if any rows are appended.
+ """
+
+ old_len = self.GetNumberRows()
+ for i in range(numRows):
+ np = ClassGroupSingleton()
+ self.__SetRow(None, np)
+
+ if self.IsModified():
+ self.__NotifyRowChanges(old_len, self.GetNumberRows())
+
+
+ID_PROPERTY_REVERT = 4002
+ID_PROPERTY_ADD = 4003
+ID_PROPERTY_GENCLASS = 4004
+ID_PROPERTY_REMOVE = 4005
+ID_PROPERTY_MOVEUP = 4006
+ID_PROPERTY_MOVEDOWN = 4007
+ID_PROPERTY_TRY = 4008
+ID_PROPERTY_EDITSYM = 4009
+ID_PROPERTY_SELECT = 4011
+ID_PROPERTY_TITLE = 4012
+ID_PROPERTY_FIELDTEXT = 4013
+
+BTN_ADD = 0
+BTN_EDIT = 1
+BTN_GEN = 2
+BTN_UP = 3
+BTN_DOWN = 4
+BTN_RM = 5
+
+EB_LAYER_TITLE = 0
+EB_SELECT_FIELD = 1
+EB_GEN_CLASS = 2
+
+class Classifier(LayerProperties):
+
+ type2string = {None: _("None"),
+ FIELDTYPE_STRING: _("Text"),
+ FIELDTYPE_INT: _("Integer"),
+ FIELDTYPE_DOUBLE: _("Decimal")}
+
+ def __init__(self, parent, name, layer, group = None):
+ """Create a Properties/Classification dialog for a layer.
+ The layer is part of map. If group is not None, select that
+ group in the classification table.
+ """
+
+ LayerProperties.__init__(self, parent, name, layer)
+
+ self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
+ self.layer_shapestore_replaced)
+
+ self.genDlg = None
+ self.group = group
+
+ LayerProperties.dialog_layout(self)
+
+ def dialog_layout(self, panel, panelBox):
+
+ if self.layer.HasClassification():
+
+ self.fieldTypeText = wx.StaticText(panel, -1, "")
+
+ self.originalClass = self.layer.GetClassification()
+ self.originalClassField = self.layer.GetClassificationColumn()
+ field = self.originalClassField
+ fieldType = self.layer.GetFieldType(field)
+
+ table = self.layer.ShapeStore().Table()
+ #
+ # make field choice box
+ #
+ self.fields = wx.Choice(panel, ID_PROPERTY_SELECT,)
+
+ self.num_cols = table.NumColumns()
+ # just assume the first field in case one hasn't been
+ # specified in the file.
+ self.__cur_field = 0
+
+ self.fields.Append("<None>")
+
+ if fieldType is None:
+ self.fields.SetClientData(0, copy.deepcopy(self.originalClass))
+ else:
+ self.fields.SetClientData(0, None)
+
+ for i in range(self.num_cols):
+ name = table.Column(i).name
+ self.fields.Append(name)
+
+ if name == field:
+ self.__cur_field = i + 1
+ self.fields.SetClientData(i + 1,
+ copy.deepcopy(self.originalClass))
+ else:
+ self.fields.SetClientData(i + 1, None)
+
+ button_gen = wx.Button(panel, ID_PROPERTY_GENCLASS,
+ _("Generate Class"))
+ button_add = wx.Button(panel, ID_PROPERTY_ADD,
+ _("Add"))
+ button_moveup = wx.Button(panel, ID_PROPERTY_MOVEUP,
+ _("Move Up"))
+ button_movedown = wx.Button(panel, ID_PROPERTY_MOVEDOWN,
+ _("Move Down"))
+ button_edit = wx.Button(panel, ID_PROPERTY_EDITSYM,
+ _("Edit Symbol"))
+ button_remove = wx.Button(panel, ID_PROPERTY_REMOVE,
+ _("Remove"))
+
+ self.classGrid = ClassGrid(panel, self)
+
+ # calling __SelectField after creating the classGrid fills in the
+ # grid with the correct information
+ self.fields.SetSelection(self.__cur_field)
+ self.__SelectField(self.__cur_field, group = self.group)
+
+
+ classBox = wx.StaticBoxSizer(
+ wx.StaticBox(panel, -1, _("Classification")), wx.VERTICAL)
+
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(wx.StaticText(panel, ID_PROPERTY_FIELDTEXT, _("Field: ")),
+ 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4)
+ sizer.Add(self.fields, 1, wx.GROW | wx.ALL, 4)
+
+ classBox.Add(sizer, 0, wx.GROW, 4)
+
+ classBox.Add(self.fieldTypeText, 0,
+ wx.GROW | wx.ALIGN_LEFT | wx.ALL | wx.ADJUST_MINSIZE, 4)
+
+ controlBox = wx.BoxSizer(wx.HORIZONTAL)
+ controlButtonBox = wx.BoxSizer(wx.VERTICAL)
+
+ controlButtonBox.Add(button_gen, 0, wx.GROW|wx.ALL, 4)
+ controlButtonBox.Add(button_add, 0, wx.GROW|wx.ALL, 4)
+ controlButtonBox.Add(button_moveup, 0, wx.GROW|wx.ALL, 4)
+ controlButtonBox.Add(button_movedown, 0, wx.GROW|wx.ALL, 4)
+ controlButtonBox.Add(button_edit, 0, wx.GROW|wx.ALL, 4)
+ controlButtonBox.Add( (60, 20), 0, wx.GROW|wx.ALL|wx.ALIGN_BOTTOM, 4)
+ controlButtonBox.Add(button_remove, 0,
+ wx.GROW|wx.ALL|wx.ALIGN_BOTTOM, 4)
+
+ controlBox.Add(self.classGrid, 1, wx.GROW, 0)
+ controlBox.Add(controlButtonBox, 0, wx.GROW, 10)
+
+ classBox.Add(controlBox, 1, wx.GROW, 10)
+ panelBox.Add(classBox, 1, wx.GROW, 0)
+
+
+ self.Bind(wx.EVT_CHOICE, self._OnFieldSelect, id=ID_PROPERTY_SELECT)
+ self.Bind(wx.EVT_BUTTON, self._OnAdd, id=ID_PROPERTY_ADD)
+ self.Bind(wx.EVT_BUTTON, self._OnEditSymbol, id=ID_PROPERTY_EDITSYM)
+ self.Bind(wx.EVT_BUTTON, self._OnRemove, id=ID_PROPERTY_REMOVE)
+ self.Bind(wx.EVT_BUTTON, self._OnGenClass, id=ID_PROPERTY_GENCLASS)
+ self.Bind(wx.EVT_BUTTON, self._OnMoveUp, id=ID_PROPERTY_MOVEUP)
+ self.Bind(wx.EVT_BUTTON, self._OnMoveDown, id=ID_PROPERTY_MOVEDOWN)
+
+ def unsubscribe_messages(self):
+ """Unsubscribe from all messages."""
+ LayerProperties.unsubscribe_messages(self)
+ self.layer.Unsubscribe(LAYER_SHAPESTORE_REPLACED,
+ self.layer_shapestore_replaced)
+
+ def layer_shapestore_replaced(self, *args):
+ """Subscribed to the map's LAYER_SHAPESTORE_REPLACED message.
+ Close self.
+ """
+ self.Close()
+
+ def EditSymbol(self, row):
+ """Open up a dialog where the user can select the properties
+ for a group.
+ """
+ table = self.classGrid.GetTable()
+ prop = table.GetValueAsCustom(row, COL_SYMBOL, None)
+
+ # get a new ClassGroupProperties object and copy the
+ # values over to our current object
+ propDlg = SelectPropertiesDialog(self, prop, self.layer.ShapeType())
+
+ self.Enable(False)
+ if propDlg.ShowModal() == wx.ID_OK:
+ new_prop = propDlg.GetClassGroupProperties()
+ table.SetValueAsCustom(row, COL_SYMBOL, None, new_prop)
+ self.Enable(True)
+ propDlg.Destroy()
+
+ def _SetClassification(self, clazz):
+ """Called from the ClassGen dialog when a new classification has
+ been created and should be set in the table.
+ """
+ # FIXME: This could be implemented using a message
+
+ self.fields.SetClientData(self.__cur_field, clazz)
+ self.classGrid.GetTable().SetClassification(clazz)
+
+ def __BuildClassification(self, fieldIndex, copyClass=False, force=False):
+ """Pack the classification setting into a Classification object.
+ Returns (Classification, fieldName) where fieldName is the selected
+ field in the table that the classification should be used with.
+ """
+
+# numRows = self.classGrid.GetNumberRows()
+# assert numRows > 0 # there should always be a default row
+
+ if fieldIndex == 0:
+ fieldName = None
+ fieldType = None
+ else:
+ fieldName = self.fields.GetString(fieldIndex)
+ fieldType = self.layer.GetFieldType(fieldName)
+
+ clazz = self.fields.GetClientData(fieldIndex)
+ if clazz is None or self.classGrid.GetTable().IsModified() or force:
+ clazz = self.classGrid.GetTable().GetClassification()
+ if copyClass:
+ clazz = copy.deepcopy(clazz)
+
+ return clazz, fieldName
+
+ def __SetGridTable(self, fieldIndex, group = None):
+ """Set the table with the classification associated with the
+ selected field at fieldIndex. Select the specified group
+ if group is not None.
+ """
+
+ clazz = self.fields.GetClientData(fieldIndex)
+
+ if clazz is None:
+ clazz = Classification()
+ clazz.SetDefaultGroup(
+ ClassGroupDefault(
+ self.layer.GetClassification().
+ GetDefaultGroup().GetProperties()))
+
+ fieldName = self.fields.GetString(fieldIndex)
+ fieldType = self.layer.GetFieldType(fieldName)
+
+ self.classGrid.CreateTable(clazz, fieldType,
+ self.layer.ShapeType(), group)
+
+ def __SetFieldTypeText(self, fieldIndex):
+ """Set the field type string using the data type of the field
+ at fieldIndex.
+ """
+ fieldName = self.fields.GetString(fieldIndex)
+ fieldType = self.layer.GetFieldType(fieldName)
+
+ assert Classifier.type2string.has_key(fieldType)
+
+ text = Classifier.type2string[fieldType]
+
+ self.fieldTypeText.SetLabel(_("Data Type: %s") % text)
+
+ def __SelectField(self, newIndex, oldIndex = -1, group = None):
+ """This method assumes that the current selection for the
+ combo has already been set by a call to SetSelection().
+ """
+
+ assert oldIndex >= -1
+
+ if oldIndex != -1:
+ clazz, name = self.__BuildClassification(oldIndex, force = True)
+ self.fields.SetClientData(oldIndex, clazz)
+
+ self.__SetGridTable(newIndex, group)
+
+ self.__EnableButtons(EB_SELECT_FIELD)
+
+ self.__SetFieldTypeText(newIndex)
+
+ def __SetTitle(self, title):
+ """Set the title of the dialog."""
+ if title != "":
+ title = ": " + title
+
+ self.SetTitle(_("Layer Properties") + title)
+
+ def _OnEditSymbol(self, event):
+ """Open up a dialog for the user to select group properties."""
+ sel = self.classGrid.GetCurrentSelection()
+
+ if len(sel) == 1:
+ self.EditSymbol(sel[0])
+
+ def _OnFieldSelect(self, event):
+ index = self.fields.GetSelection()
+ self.__SelectField(index, self.__cur_field)
+ self.__cur_field = index
+
+ def OnTry(self, event):
+ """Put the data from the table into a new Classification and hand
+ it to the layer.
+ """
+
+ if self.layer.HasClassification():
+ clazz = self.fields.GetClientData(self.__cur_field)
+
+ #
+ # only build the classification if there wasn't one to
+ # to begin with or it has been modified
+ #
+ self.classGrid.SaveEditControlValue()
+ clazz, name = self.__BuildClassification(self.__cur_field, True)
+
+ self.layer.SetClassificationColumn(name)
+ self.layer.SetClassification(clazz)
+
+ self.haveApplied = True
+
+ def OnOK(self, event):
+ self.OnTry(event)
+ self.Close()
+
+ def OnRevert(self, event):
+ """The layer's current classification stays the same."""
+ if self.haveApplied and self.layer.HasClassification():
+ self.layer.SetClassificationColumn(self.originalClassField)
+ self.layer.SetClassification(self.originalClass)
+
+ #self.Close()
+
+ def _OnAdd(self, event):
+ self.classGrid.AppendRows()
+
+ def _OnRemove(self, event):
+ self.classGrid.DeleteSelectedRows()
+
+ def _OnGenClass(self, event):
+ """Open up a dialog for the user to generate classifications."""
+
+ self.genDlg = ClassGenDialog(self, self.layer,
+ self.fields.GetString(self.__cur_field))
+
+ self.Bind(wx.EVT_CLOSE, self._OnGenDialogClose, self.genDlg)
+
+ self.__EnableButtons(EB_GEN_CLASS)
+
+ self.genDlg.Show()
+
+ def _OnGenDialogClose(self, event):
+ """Reenable buttons after the generate classification
+ dialog is closed.
+ """
+ self.genDlg.Destroy()
+ self.genDlg = None
+ self.__EnableButtons(EB_GEN_CLASS)
+
+ def _OnMoveUp(self, event):
+ """When the user clicks MoveUp, try to move a group up one row."""
+ sel = self.classGrid.GetCurrentSelection()
+
+ if len(sel) == 1:
+ i = sel[0]
+ if i > 1:
+ table = self.classGrid.GetTable()
+ x = table.GetClassGroup(i - 1)
+ y = table.GetClassGroup(i)
+ table.SetClassGroup(i - 1, y)
+ table.SetClassGroup(i, x)
+ self.classGrid.ClearSelection()
+ self.classGrid.SelectRow(i - 1)
+ self.classGrid.MakeCellVisible(i - 1, 0)
+
+ def _OnMoveDown(self, event):
+ """When the user clicks MoveDown, try to move a group down one row."""
+ sel = self.classGrid.GetCurrentSelection()
+
+ if len(sel) == 1:
+ i = sel[0]
+ table = self.classGrid.GetTable()
+ if 0 < i < table.GetNumberRows() - 1:
+ x = table.GetClassGroup(i)
+ y = table.GetClassGroup(i + 1)
+ table.SetClassGroup(i, y)
+ table.SetClassGroup(i + 1, x)
+ self.classGrid.ClearSelection()
+ self.classGrid.SelectRow(i + 1)
+ self.classGrid.MakeCellVisible(i + 1, 0)
+
+ def _OnTitleChanged(self, event):
+ """Update the dialog title when the user changed the layer name."""
+ obj = event.GetEventObject()
+
+ self.layer.SetTitle(obj.GetValue())
+ self.__SetTitle(self.layer.Title())
+
+ self.__EnableButtons(EB_LAYER_TITLE)
+
+ def __EnableButtons(self, case):
+ """Helper method that enables/disables the appropriate buttons
+ based on the case provided. Cases are constants beginning with EB_.
+ """
+
+ list = {wx.ID_OK : True,
+ wx.ID_CANCEL : True,
+ ID_PROPERTY_ADD : True,
+ ID_PROPERTY_MOVEUP : True,
+ ID_PROPERTY_MOVEDOWN : True,
+ ID_PROPERTY_REMOVE : True,
+ ID_PROPERTY_SELECT : True,
+ ID_PROPERTY_FIELDTEXT : True,
+ ID_PROPERTY_GENCLASS : True,
+ ID_PROPERTY_EDITSYM : True}
+
+ if case == EB_LAYER_TITLE:
+ if self.layer.Title() == "":
+ list[wxID_OK] = False
+ list[wxID_CANCEL] = False
+
+ elif case == EB_SELECT_FIELD:
+ if self.fields.GetSelection() == 0:
+ list[ID_PROPERTY_GENCLASS] = False
+ list[ID_PROPERTY_ADD] = False
+ list[ID_PROPERTY_MOVEUP] = False
+ list[ID_PROPERTY_MOVEDOWN] = False
+ list[ID_PROPERTY_REMOVE] = False
+
+ elif case == EB_GEN_CLASS:
+ if self.genDlg is not None:
+ list[ID_PROPERTY_SELECT] = False
+ list[ID_PROPERTY_FIELDTEXT] = False
+ list[ID_PROPERTY_GENCLASS] = False
+
+ for id, enable in list.items():
+ win = self.FindWindowById(id)
+ if win:
+ win.Enable(enable)
+
+ID_SELPROP_SPINCTRL_LINEWIDTH = 4002
+ID_SELPROP_PREVIEW = 4003
+ID_SELPROP_STROKECLR = 4004
+ID_SELPROP_FILLCLR = 4005
+ID_SELPROP_STROKECLRTRANS = 4006
+ID_SELPROP_FILLCLRTRANS = 4007
+ID_SELPROP_SPINCTRL_SIZE = 4008
+
+class SelectPropertiesDialog(wx.Dialog):
+ """Dialog that allows the user to select group properties."""
+
+ def __init__(self, parent, prop, shapeType):
+ """Open the dialog with the initial prop properties and shapeType."""
+
+ wx.Dialog.__init__(self, parent, -1, _("Select Properties"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+
+ self.prop = ClassGroupProperties(prop)
+
+ topBox = wx.BoxSizer(wx.VERTICAL)
+
+ itemBox = wx.BoxSizer(wx.HORIZONTAL)
+
+ # preview box
+ previewBox = wx.BoxSizer(wx.VERTICAL)
+ previewBox.Add(wx.StaticText(self, -1, _("Preview:")),
+ 0, wx.ALIGN_LEFT | wx.ALL, 4)
+
+ self.previewWin = ClassGroupPropertiesCtrl(
+ self, ID_SELPROP_PREVIEW, self.prop, shapeType,
+ (40, 40), wx.SIMPLE_BORDER)
+
+ self.previewWin.AllowEdit(False)
+
+ previewBox.Add(self.previewWin, 1, wx.GROW | wx.ALL, 4)
+
+ itemBox.Add(previewBox, 1, wx.ALIGN_LEFT | wx.ALL | wx.GROW, 0)
+
+ # control box
+ ctrlBox = wx.BoxSizer(wx.VERTICAL)
+
+ lineColorBox = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, ID_SELPROP_STROKECLR, _("Change Line Color"))
+ button.SetFocus()
+ lineColorBox.Add(button, 1, wx.ALL | wx.GROW, 4)
+ self.Bind(wx.EVT_BUTTON, self._OnChangeLineColor, id=ID_SELPROP_STROKECLR)
+
+ lineColorBox.Add(
+ wx.Button(self, ID_SELPROP_STROKECLRTRANS, _("Transparent")),
+ 1, wx.ALL | wx.GROW, 4)
+ self.Bind(wx.EVT_BUTTON, self._OnChangeLineColorTrans, \
+ id=ID_SELPROP_STROKECLRTRANS)
+
+ ctrlBox.Add(lineColorBox, 0,
+ wx.ALIGN_CENTER_HORIZONTAL | wx.ALL | wx.GROW, 4)
+
+ if shapeType != SHAPETYPE_ARC:
+ fillColorBox = wx.BoxSizer(wx.HORIZONTAL)
+ fillColorBox.Add(
+ wx.Button(self, ID_SELPROP_FILLCLR, _("Change Fill Color")),
+ 1, wx.ALL | wx.GROW, 4)
+ self.Bind(wx.EVT_BUTTON, self._OnChangeFillColor, id=ID_SELPROP_FILLCLR)
+ fillColorBox.Add(
+ wx.Button(self, ID_SELPROP_FILLCLRTRANS, _("Transparent")),
+ 1, wx.ALL | wx.GROW, 4)
+ self.Bind(wx.EVT_BUTTON, self._OnChangeFillColorTrans,\
+ id=ID_SELPROP_FILLCLRTRANS)
+ ctrlBox.Add(fillColorBox, 0,
+ wx.ALIGN_CENTER_HORIZONTAL | wx.ALL | wx.GROW, 4)
+
+ # Line width selection
+ spinBox = wx.BoxSizer(wx.HORIZONTAL)
+ spinBox.Add(wx.StaticText(self, -1, _("Line Width: ")),
+ 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4)
+ self.spinCtrl_linewidth = wx.SpinCtrl(self,
+ ID_SELPROP_SPINCTRL_LINEWIDTH,
+ min=1, max=10,
+ value=str(prop.GetLineWidth()),
+ initial=prop.GetLineWidth())
+
+ self.Bind(wx.EVT_SPINCTRL, self._OnSpinLineWidth, \
+ id=ID_SELPROP_SPINCTRL_LINEWIDTH)
+
+ spinBox.Add(self.spinCtrl_linewidth, 0, wx.ALIGN_LEFT | wx.ALL, 4)
+ ctrlBox.Add(spinBox, 0, wx.ALIGN_RIGHT | wx.ALL, 0)
+
+ # Size selection
+ if shapeType == SHAPETYPE_POINT:
+ spinBox = wx.BoxSizer(wx.HORIZONTAL)
+ spinBox.Add(wx.StaticText(self, -1, _("Size: ")),
+ 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4)
+ self.spinCtrl_size = wx.SpinCtrl(self, ID_SELPROP_SPINCTRL_SIZE,
+ min=1, max=100,
+ value=str(prop.GetSize()),
+ initial=prop.GetSize())
+
+ self.Bind(wx.EVT_SPINCTRL, self._OnSpinSize, id=ID_SELPROP_SPINCTRL_SIZE)
+
+ spinBox.Add(self.spinCtrl_size, 0, wx.ALIGN_LEFT | wx.ALL, 4)
+ ctrlBox.Add(spinBox, 0, wx.ALIGN_RIGHT | wx.ALL, 0)
+
+
+ itemBox.Add(ctrlBox, 0, wx.ALIGN_RIGHT | wx.ALL | wx.GROW, 0)
+ topBox.Add(itemBox, 1, wx.ALIGN_LEFT | wx.ALL | wx.GROW, 0)
+
+ #
+ # Control buttons:
+ #
+ buttonBox = wx.BoxSizer(wx.HORIZONTAL)
+ button_ok = wx.Button(self, wx.ID_OK, _("OK"))
+ buttonBox.Add(button_ok, 0, wx.RIGHT|wx.EXPAND, 10)
+ buttonBox.Add(wx.Button(self, wx.ID_CANCEL, _("Cancel")),
+ 0, wx.RIGHT|wx.EXPAND, 10)
+ topBox.Add(buttonBox, 0, wx.ALIGN_RIGHT|wx.BOTTOM|wx.TOP, 10)
+
+ button_ok.SetDefault()
+
+ #EVT_BUTTON(self, wxID_OK, self._OnOK)
+ #EVT_BUTTON(self, ID_SELPROP_CANCEL, self._OnCancel)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(topBox)
+ topBox.Fit(self)
+ topBox.SetSizeHints(self)
+
+ def OnOK(self, event):
+ self.EndModal(wx.ID_OK)
+
+ def OnCancel(self, event):
+ self.EndModal(wx.ID_CANCEL)
+
+ def _OnSpinLineWidth(self, event):
+ self.prop.SetLineWidth(self.spinCtrl_linewidth.GetValue())
+ self.previewWin.Refresh()
+
+ def _OnSpinSize(self, event):
+ self.prop.SetSize(self.spinCtrl_size.GetValue())
+ self.previewWin.Refresh()
+
+ def __GetColor(self, cur):
+ dialog = ColorDialog(self)
+ dialog.SetColor(cur)
+
+ ret = None
+ if dialog.ShowModal() == wx.ID_OK:
+ ret = dialog.GetColor()
+
+ dialog.Destroy()
+
+ return ret
+
+ def _OnChangeLineColor(self, event):
+ clr = self.__GetColor(self.prop.GetLineColor())
+ if clr is not None:
+ self.prop.SetLineColor(clr)
+ self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
+
+ def _OnChangeLineColorTrans(self, event):
+ self.prop.SetLineColor(Transparent)
+ self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
+
+ def _OnChangeFillColor(self, event):
+ clr = self.__GetColor(self.prop.GetFill())
+ if clr is not None:
+ self.prop.SetFill(clr)
+ self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
+
+ def _OnChangeFillColorTrans(self, event):
+ self.prop.SetFill(Transparent)
+ self.previewWin.Refresh() # XXX: work around, see ClassDataPreviewer
+
+ def GetClassGroupProperties(self):
+ return self.prop
+
+
+class ClassDataPreviewWindow(wx.Window):
+ """A custom window that draws group properties using the correct shape."""
+
+ def __init__(self, rect, prop, shapeType,
+ parent = None, id = -1, size = wx.DefaultSize):
+ """Draws the appropriate shape as specified with shapeType using
+ prop properities.
+ """
+ if parent is not None:
+ wx.Window.__init__(self, parent, id, (0, 0), size)
+ self.Bind(wx.EVT_PAINT, self._OnPaint)
+
+ self.rect = rect
+
+ self.prop = prop
+ self.shapeType = shapeType
+ self.previewer = ClassDataPreviewer()
+
+ def GetProperties():
+ return self.prop
+
+ def _OnPaint(self, event):
+ dc = wx.PaintDC(self)
+
+ # XXX: this doesn't seem to be having an effect:
+ dc.DestroyClippingRegion()
+
+ if self.rect is None:
+ w, h = self.GetSize()
+ rect = wx.Rect(0, 0, w, h)
+ else:
+ rect = self.rect
+
+ self.previewer.Draw(dc, rect, self.prop, self.shapeType)
+
+class ClassDataPreviewer:
+ """Class that actually draws a group property preview."""
+
+ def Draw(self, dc, rect, prop, shapeType):
+ """Draw the property.
+
+ returns: (w, h) as adapted extend if the drawing size
+ exceeded the given rect. This can only be the case
+ for point symbols. If the symbol fits the given rect,
+ None is returned.
+ """
+
+ assert dc is not None
+ assert isinstance(prop, ClassGroupProperties)
+
+ if rect is None:
+ x = 0
+ y = 0
+ w, h = dc.GetSize()
+ else:
+ x = rect.GetX()
+ y = rect.GetY()
+ w = rect.GetWidth()
+ h = rect.GetHeight()
+
+ stroke = prop.GetLineColor()
+ if stroke is Transparent:
+ pen = wx.TRANSPARENT_PEN
+ else:
+ pen = wx.Pen(Color2wxColour(stroke),
+ prop.GetLineWidth(),
+ wx.SOLID)
+
+ stroke = prop.GetFill()
+ if stroke is Transparent:
+ brush = wx.TRANSPARENT_BRUSH
+ else:
+ brush = wx.Brush(Color2wxColour(stroke), wx.SOLID)
+
+ dc.SetPen(pen)
+ dc.SetBrush(brush)
+
+ if shapeType == SHAPETYPE_ARC:
+ dc.DrawSpline([wx.Point(x, y + h),
+ wx.Point(x + w/2, y + h/4),
+ wx.Point(x + w/2, y + h/4*3),
+ wx.Point(x + w, y)])
+
+ elif shapeType == SHAPETYPE_POINT:
+
+ dc.DrawCircle(x + w/2, y + h/2, prop.GetSize())
+ circle_size = prop.GetSize() * 2 + prop.GetLineWidth() * 2
+ new_h = h
+ new_w = w
+ if h < circle_size: new_h = circle_size
+ if w < circle_size: new_w = circle_size
+ if new_h > h or new_w > w:
+ return (new_w, new_h)
+
+ elif shapeType == SHAPETYPE_POLYGON:
+ dc.DrawRectangle(x, y, w, h)
+
+ return None
+
+class ClassRenderer(grid.PyGridCellRenderer):
+ """A wrapper class that can be used to draw group properties in a
+ grid table.
+ """
+
+ def __init__(self, shapeType):
+ grid.PyGridCellRenderer.__init__(self)
+ self.shapeType = shapeType
+ self.previewer = ClassDataPreviewer()
+
+ def Draw(self, grid, attr, dc, rect, row, col, isSelected):
+ data = grid.GetTable().GetClassGroup(row)
+
+ dc.SetClippingRegion(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+ dc.SetPen(wx.Pen(wx.LIGHT_GREY))
+ dc.SetBrush(wx.Brush(wx.LIGHT_GREY, wx.SOLID))
+ dc.DrawRectangle(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+
+ if not isinstance(data, ClassGroupMap):
+ new_size = self.previewer.Draw(dc, rect, data.GetProperties(),
+ self.shapeType)
+ if new_size is not None:
+ (new_w, new_h) = new_size
+ grid.SetRowSize(row, new_h)
+ grid.SetColSize(col, new_h)
+ grid.ForceRefresh()
+
+ # now that we know the height, redraw everything
+ rect.SetHeight(new_h)
+ rect.SetWidth(new_w)
+ dc.DestroyClippingRegion()
+ dc.SetClippingRegion(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+ dc.SetPen(wx.Pen(wx.LIGHT_GREY))
+ dc.SetBrush(wx.Brush(wx.LIGHT_GREY, wx.SOLID))
+ dc.DrawRectangle(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+ self.previewer.Draw(dc, rect, data.GetProperties(),
+ self.shapeType)
+
+ if isSelected:
+ dc.SetPen(wx.Pen(wx.BLACK, 1, wx.SOLID))
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+ dc.DrawRectangle(rect.GetX(), rect.GetY(),
+ rect.GetWidth(), rect.GetHeight())
+
+ dc.DestroyClippingRegion()
+
+
+class ClassGroupPropertiesCtrl(wx.Control):
+ """A custom window and control that draw a preview of group properties
+ and can open a dialog to modify the properties if the user double-clicks
+ it.
+ """
+
+ def __init__(self, parent, id, props, shapeType,
+ size = wx.DefaultSize, style = 0):
+ wx.Control.__init__(self, parent, id, size = size, style = style)
+
+ self.parent = parent
+
+ self.SetProperties(props)
+ self.SetShapeType(shapeType)
+ self.AllowEdit(True)
+
+ self.Bind(wx.EVT_PAINT, self._OnPaint)
+ self.Bind(wx.EVT_LEFT_DCLICK, self._OnLeftDClick)
+
+ self.previewer = ClassDataPreviewer()
+
+ def _OnPaint(self, event):
+ dc = wx.PaintDC(self)
+
+ # XXX: this doesn't seem to be having an effect:
+ dc.DestroyClippingRegion()
+
+ w, h = self.GetClientSize()
+
+ self.previewer.Draw(dc,
+ wx.Rect(0, 0, w, h),
+ self.GetProperties(),
+ self.GetShapeType())
+
+
+ def GetProperties(self):
+ return self.props
+
+ def SetProperties(self, props):
+ self.props = props
+ self.Refresh()
+
+ def GetShapeType(self):
+ return self.shapeType
+
+ def SetShapeType(self, shapeType):
+ self.shapeType = shapeType
+ self.Refresh()
+
+ def AllowEdit(self, allow):
+ """Allow/Disallow double-clicking on the control."""
+ self.allowEdit = allow
+
+ def DoEdit(self):
+ """Open the properties selector dialog."""
+
+ if not self.allowEdit: return
+
+ propDlg = SelectPropertiesDialog(self.parent,
+ self.GetProperties(),
+ self.GetShapeType())
+
+ if propDlg.ShowModal() == wx.ID_OK:
+ new_prop = propDlg.GetClassGroupProperties()
+ self.SetProperties(new_prop)
+ self.Refresh()
+
+ propDlg.Destroy()
+
+ def _OnLeftDClick(self, event):
+ self.DoEdit()
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/colordialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/colordialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/colordialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,136 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagnber <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: colordialog.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import wx
+
+from Thuban import _
+
+from Thuban.UI.common import Color2wxColour, wxColour2Color
+
+from Thuban.Model.color import Transparent
+
+
+# determine whether the pyColourChooserDialog is available
+# It was not available with the very first versions of wxWindows 2.4
+# (I don't know the exact version though)
+try:
+ from wxPython.lib.colourchooser import wxPyColourChooser
+ _wxPyColourChooser = True
+ wx.InitAllImageHandlers() # should be somewhere at Thuban startup?
+except:
+ _wxPyColourChooser = False
+
+
+class PyColorChooserDialog(wx.Dialog):
+ """
+ A Dialog that uses the wxPyColourChooser Frame and simply
+ adds OK and Cancel button to form a modal color selection dialog.
+ """
+
+ def __init__(self, parent):
+ wx.Dialog.__init__(self, parent, -1, _("Select Color"))
+
+ self.parent = parent
+ self.dialog_layout()
+
+ def dialog_layout(self):
+ top_box = wx.BoxSizer(wx.VERTICAL)
+
+ self.chooser = wxPyColourChooser(self, -1)
+
+ top_box.Add(self.chooser, 1, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 5)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.Button(self, wx.ID_OK, _("OK")), 0, wx.ALL, 4)
+ box.Add(wx.Button(self, wx.ID_CANCEL, _("Cancel")), 0, wx.ALL, 4)
+ top_box.Add(box, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=wx.ID_CANCEL)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(top_box)
+ top_box.Fit(self)
+ top_box.SetSizeHints(self)
+
+ def GetValue(self):
+ return self.chooser.GetValue()
+
+ def SetValue(self, color):
+ return self.chooser.SetValue(color)
+
+ def OnOK(self, event):
+ self.EndModal(wx.ID_OK)
+
+ def OnCancel(self, event):
+ self.EndModal(wx.ID_CANCEL)
+
+
+class ColorDialog:
+ """
+ The color dialog raises one of the available color selection
+ dialogs. ColorDialog is no derived from any GUI class though.
+
+ Furthermore, wxColour class is mapped to the Thuban
+ Color class already through this class.
+
+ Eventually it should be configurable globally for Thuban
+ which color dialog to use since they might differ in
+ functionality, translation or stability.
+ """
+
+ def __init__(self, parent):
+ if _wxPyColourChooser:
+ self.dlg = PyColorChooserDialog(parent)
+ else:
+ self.dlg = wx.ColourDialog(parent)
+
+ def GetColor(self):
+ if _wxPyColourChooser:
+ return wxColour2Color(self.dlg.GetValue())
+ else:
+ return wxColour2Color(self.dlg.GetColourData().GetColour())
+
+ def SetColor(self, color):
+ if color is not Transparent:
+ if _wxPyColourChooser:
+ self.dlg.SetValue(Color2wxColour(color))
+ else:
+ self.dlg.GetColourData().SetColour(Color2wxColour(color))
+
+ def ShowModal(self):
+ return self.dlg.ShowModal()
+
+ def Destroy(self):
+ return self.dlg.Destroy()
+
+
+if __name__ == "__main__":
+ # Test routine to run the dialog without Thuban
+
+ from wxPython.wx import wxApp, NULL
+
+ wx.InitAllImageHandlers()
+
+ class _TestApp(wx.App):
+ def OnInit(self):
+ dialog = ColorDialog(NULL)
+
+ if dialog.ShowModal() == wx.ID_OK:
+ print "Selected color:", dialog.GetColor()
+ else:
+ print "No color selected"
+
+ dialog.Destroy()
+ return True
+
+ app = _TestApp()
+ app.MainLoop()
Added: packages/thuban/branches/upstream/current/Thuban/UI/command.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/command.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/command.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,154 @@
+# Copyright (C) 2001, 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Command Objects.
+
+Command objects represent a command that a user can invoke and act as
+mediators between the GUI and the application.
+
+This module also defines a command registry that maps command names to
+command objects.
+"""
+
+__version__ = "$Revision: 2700 $"
+
+
+from types import TupleType
+
+
+class Command:
+
+ """
+ Represent a single command.
+
+ A command is identified by a name, it has a title (used in menu
+ items and buttons, etc) and a callable object that can be invoked
+ with the context as a single parameter. The context is an object
+ with a few public attributes for the application object, the session
+ and the main window.
+
+ Additionally, a command may have functions that can determine
+ whether the command can be invoked or whether it is checked in case
+ of a toggled command. These functions are called with just the
+ context as parameters.
+ """
+
+ args = ()
+ kwargs = None
+ sensitive = None
+ checked = None
+ dyntext = None
+
+ def __init__(self, name, title, function, helptext = "", icon = "",
+ args = (), kwargs = None,
+ sensitive = None, checked = None, dyntext = None):
+ self.name = name
+ self.title = title
+ self.function = function
+ self.helptext = helptext
+ self.icon = icon
+ if args != ():
+ if type(args) != TupleType:
+ args = (args,)
+ self.args = args
+ if kwargs is not None:
+ self.kwargs = kwargs
+ if sensitive is not None:
+ self.sensitive = sensitive
+ if checked is not None:
+ self.checked = checked
+ if dyntext is not None:
+ self.dyntext = dyntext
+
+ def Name(self):
+ return self.name
+
+ def Title(self):
+ return self.title
+
+ def HelpText(self):
+ return self.helptext
+
+ def Icon(self):
+ return self.icon
+
+ def Sensitive(self, context):
+ if self.sensitive is not None:
+ return self.sensitive(context)
+ return 1
+
+ def Checked(self, context):
+ if self.checked is not None:
+ return self.checked(context)
+ return 0 # XXX raise an exception?
+
+ def IsCheckCommand(self):
+ return self.checked is not None
+
+ def DynText(self, context):
+ if self.dyntext is not None:
+ return self.dyntext(context)
+ return self.Title()
+
+ def HasDynText(self):
+ return self.dyntext is not None
+
+ def IsDynamic(self):
+ """Return true if the command is in any way dynamic"""
+ return (self.sensitive is not None
+ or self.checked is not None
+ or self.dyntext is not None)
+
+ def IsTool(self):
+ """Return whether the command represents a tool.
+
+ This default implementation always returns 0.
+ """
+ return 0
+
+ def Execute(self, context, args = ()):
+ kw = self.kwargs
+ if kw is None:
+ kw = {}
+ if type(args) != TupleType:
+ args = (args,)
+ #print self.name, self.args, args
+ apply(self.function, (context,) + self.args + args, kw)
+
+class ToolCommand(Command):
+
+ """A command tool activating a tool"""
+
+ def IsTool(self):
+ """Return whether the command represents a tool, i.e. always 1"""
+ return 1
+
+
+class CommandRegistry:
+
+ """
+ A CommandRegistry maps command names to command objects
+ """
+
+ def __init__(self):
+ self.registry = {}
+
+ def Add(self, script):
+ self.registry[script.name] = script
+
+ def AddFunction(self, name, title, function, args = (), sensitive = None):
+ self.Add(Command(name, title, function, args = args,
+ sensitive = sensitive))
+
+ def Command(self, name):
+ return self.registry.get(name, None)
+
+
+
+# The central command registry
+registry = CommandRegistry()
Added: packages/thuban/branches/upstream/current/Thuban/UI/common.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/common.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/common.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,52 @@
+# Copyright (c) 2001, 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Miscellaneous UI related functions"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: common.py 2700 2006-09-18 14:27:02Z dpinte $
+
+
+from Thuban.Model.color import Color
+import wx
+
+def Color2wxColour(color):
+ """Return a wxColor object for the Thuban color object color"""
+ return wx.Colour(int(round(color.red * 255)),
+ int(round(color.green * 255)),
+ int(round(color.blue * 255)))
+
+def wxColour2Color(colour):
+ """Return a Thuban color object for the wxColor object color"""
+ assert(colour is not None)
+ # this doesn't work because colour is really a wxColourPtr!
+ #assert(isinstance(colour, wxColour))
+ return Color(colour.Red() / 255.0,
+ colour.Green() / 255.0,
+ colour.Blue() / 255.0)
+
+def ThubanBeginBusyCursor():
+ """Thuban wrapper for wxBeginBusyCursor
+
+ In addition to calling wxBeginBusyCursor this function also calls
+ wxSafeYield to make sure that the cursor change takes effect. wxGTK
+ 2.4 at least doesn't do that automatically.
+
+ This function and the corresponding ThubanEndBusyCursor function are
+ the functions to use in Thuban to set a busy cursor.
+ """
+ wx.BeginBusyCursor()
+ wx.SafeYield()
+
+def ThubanEndBusyCursor():
+ """Thuban wrapper for wxEndBusyCursor
+
+ This function doesn't do anything more than calling wxEndBusyCursor
+ yet, but please use this whereever you use ThubanBeginBusyCursor.
+ """
+ wx.EndBusyCursor()
Added: packages/thuban/branches/upstream/current/Thuban/UI/context.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/context.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/context.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,29 @@
+# Copyright (C) 2001, 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+The command execution context,
+"""
+
+__version__ = "$Revision: 374 $"
+
+class Context:
+
+ """Command Execution Context
+
+ Public Attributes:
+
+ application -- The application object
+ session -- The session object
+ mainwindow -- The main window
+
+ """
+
+ def __init__(self, application, session, mainwindow):
+ self.application = application
+ self.session = session
+ self.mainwindow = mainwindow
Added: packages/thuban/branches/upstream/current/Thuban/UI/controls.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/controls.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/controls.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,230 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""Common Thuban specific control widgets"""
+
+__version__ = "$Revision: 2718 $"
+
+import wx
+from wx import grid
+
+from Thuban import _
+
+# FIXME: the wx_value_type_map should be moved from tableview to a
+# separate module
+from tableview import wx_value_type_map
+
+
+
+class RecordListCtrl(wx.ListCtrl):
+
+ """List Control showing a single record from a thuban table"""
+
+ def __init__(self, parent, id):
+ wx.ListCtrl.__init__(self, parent, id, style = wx.LC_REPORT)
+
+ self.InsertColumn(0, _("Field"))
+ self.SetColumnWidth(0, 200)
+ self.InsertColumn(1, _("Value"))
+ self.SetColumnWidth(1, 100)
+
+ # vaues maps row numbers to the corresponding python values
+ self.values = {}
+
+ def fill_list(self, table, shape):
+ """Fill self with the contents shape's record from table"""
+ self.DeleteAllItems()
+ values = {}
+
+ if shape is not None:
+ names = []
+ for col in table.Columns():
+ names.append(col.name)
+ record = table.ReadRowAsDict(shape)
+
+ for i in range(len(names)):
+ name = names[i]
+ value = record[name]
+ self.InsertStringItem(i, name)
+ self.SetStringItem(i, 1, str(value).decode('iso-8859-1'))
+ values[i] = value
+
+ self.values = values
+
+class SelectableRecordListCtrl(RecordListCtrl):
+
+ def __init__(self, parent, id):
+ RecordListCtrl.__init__(self, parent, id)
+
+ # selected is the index of the selected record or -1 if none is
+ # selected
+ self.selected = -1
+ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=self.GetId())
+
+ def OnItemSelected(self, event):
+ """Event handler. Update the selected instvar"""
+ self.selected = event.m_itemIndex
+
+ def GetValue(self):
+ """Return the currently selected value. None if no value is selected"""
+ if self.selected >= 0:
+ return self.values[self.selected]
+ else:
+ return None
+
+
+class RecordTable(grid.PyGridTableBase):
+
+ """Wrapper that makes a Thuban table record look like a table for a
+ wxGrid
+ """
+
+ def __init__(self, table = None, record = None):
+ grid.PyGridTableBase.__init__(self)
+ self.num_cols = 1
+ self.num_rows = 0
+ self.table = None
+ self.record_index = record
+ self.record = None
+ self.SetTable(table, record)
+
+ def SetTable(self, table, record_index):
+ old_num_rows = self.num_rows
+ if record_index is not None:
+ self.table = table
+ self.record_index = record_index
+ self.record = table.ReadRowAsDict(record_index)
+
+ # we have one row for each field in the table
+ self.num_rows = table.NumColumns()
+
+ # extract the field types and names of the row we're showing.
+ self.rows = []
+ for i in range(self.num_rows):
+ col = table.Column(i)
+ self.rows.append((col.name, wx_value_type_map[col.type]))
+ self.notify_get_values()
+ else:
+ # make the grid empty
+ self.num_rows = 0
+ self.rows = []
+
+ # notify the views if the number of rows has changed
+ if self.num_rows > old_num_rows:
+ self.notify_append_rows(self.num_rows - old_num_rows)
+ elif self.num_rows < old_num_rows:
+ self.notify_delete_rows(0, old_num_rows - self.num_rows)
+
+ def notify_append_rows(self, num):
+ """Tell the view that num rows were appended"""
+ self.send_view_message(grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, num)
+
+ def notify_delete_rows(self, start, num):
+ """Tell the view that num rows were deleted starting at start"""
+ self.send_view_message(grid.GRIDTABLE_NOTIFY_ROWS_DELETED, start, num)
+
+ def notify_get_values(self):
+ """Tell the view that the grid's values have to be updated"""
+ self.send_view_message(grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
+
+ def send_view_message(self, msgid, *args):
+ """Send the message msgid to the view with arguments args"""
+ view = self.GetView()
+ if view:
+ #print "send_view_message", msgid, args
+ msg = apply(grid.GridTableMessage, (self, msgid) + args)
+ view.ProcessTableMessage(msg)
+
+ #
+ # required methods for the wxPyGridTableBase interface
+ #
+
+ def GetNumberRows(self):
+ return self.num_rows
+
+ def GetNumberCols(self):
+ return self.num_cols
+
+ def IsEmptyCell(self, row, col):
+ return row >= self.num_rows or col >= self.num_cols
+
+ # Get/Set values in the table. The Python version of these
+ # methods can handle any data-type, (as long as the Editor and
+ # Renderer understands the type too,) not just strings as in the
+ # C++ version.
+ def GetValue(self, row, col):
+ if row < self.num_rows:
+ return self.record[self.rows[row][0]]
+ return ""
+
+ def SetValue(self, row, col, value):
+ if row < self.num_rows:
+ name = self.rows[row][0]
+ self.record[name] = value
+ self.table.write_record(self.record_index, {name: value})
+
+ #
+ # Some optional methods
+ #
+
+ # Called when the grid needs to display labels
+ def GetColLabelValue(self, col):
+ return _("Value")
+
+ def GetRowLabelValue(self, row):
+ if row < self.num_rows:
+ return self.rows[row][0]
+ return ""
+
+ # Called to determine the kind of editor/renderer to use by
+ # default, doesn't necessarily have to be the same type used
+ # nativly by the editor/renderer if they know how to convert.
+ def GetTypeName(self, row, col):
+ # for some reason row and col may be negative sometimes, but
+ # it's probably a wx bug (filed as #593189 on sourceforge)
+ if 0 <= row < self.num_rows:
+ return self.rows[row][1]
+ return grid.GRID_VALUE_STRING
+
+ # Called to determine how the data can be fetched and stored by the
+ # editor and renderer. This allows you to enforce some type-safety
+ # in the grid.
+ def CanGetValueAs(self, row, col, typeName):
+ # perhaps we should allow conversion int->double?
+ return self.GetTypeName(row, col) == typeName
+
+ def CanSetValueAs(self, row, col, typeName):
+ return self.CanGetValueAs(row, col, typeName)
+
+
+
+class RecordGridCtrl(grid.Grid):
+
+ """Grid view for a RecordTable"""
+
+ def __init__(self, parent, table = None, record = None):
+ grid.Grid.__init__(self, parent, -1)
+
+ self.table = RecordTable(table, record)
+
+ # The second parameter means that the grid is to take ownership
+ # of the table and will destroy it when done. Otherwise you
+ # would need to keep a reference to it and call it's Destroy
+ # method later.
+ self.SetTable(self.table, True)
+
+ #self.SetMargins(0,0)
+ self.AutoSizeColumn(0, True)
+
+ #self.SetSelectionMode(wxGrid.wxGridSelectRows)
+
+ #EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
+ #EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
+
+ def SetTableRecord(self, table, record):
+ self.table.SetTable(table, record)
Added: packages/thuban/branches/upstream/current/Thuban/UI/dbdialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/dbdialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/dbdialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,390 @@
+# Copyright (c) 2001, 2003, 2004 by Intevation GmbH
+# Authors:
+# Martin Mueller <mmueller at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""Dialogs to manage database connections"""
+
+import sys, traceback
+
+import wx
+
+try:
+ import psycopg
+except ImportError:
+ psycopg = None
+
+from Thuban import _
+from Thuban.UI.dialogs import NonModalDialog
+from Thuban.Model.table import FIELDTYPE_INT
+from Thuban.Model.postgisdb import ConnectionError, PostGISConnection
+from Thuban.Model.messages import DBCONN_ADDED, DBCONN_REMOVED
+from messages import SESSION_REPLACED
+
+
+ID_DB_ADD = 9101
+ID_DB_REMOVE = 9102
+
+ID_DBCHOOSE_RETRIEVE = 9201
+ID_DBCHOOSE_OK = 9202
+ID_DBCHOOSE_CANCEL = 9203
+ID_LB_DCLICK = 9204
+
+
+class ChooseDBTableDialog(wx.Dialog):
+
+ def __init__(self, parent, session):
+ wx.Dialog.__init__(self, parent, -1, _("Choose layer from database"),
+ style = wx.DIALOG_MODAL|wx.CAPTION)
+ self.session = session
+ self.dbconns = self.session.DBConnections()
+ self.tables = []
+
+ #
+ # Build the dialog
+ #
+
+ # Sizer for the entire dialog
+ top = wx.FlexGridSizer(2, 1, 0, 0)
+
+ # Sizer for the main part with the list boxes
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ top.Add(main_sizer, 1, wx.EXPAND, 0)
+
+ # The list box with the connections
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, _("Databases")),
+ wx.HORIZONTAL)
+ self.lb_connections = wx.ListBox(self, -1)
+ static_box.Add(self.lb_connections, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ for i in range(len(self.dbconns)):
+ self.lb_connections.Append(self.dbconns[i].BriefDescription())
+ if self.lb_connections.GetCount() > 0:
+ self.lb_connections.SetSelection(0, True)
+
+ # The button box between the connections list box and the table
+ # list box
+ buttons = wx.FlexGridSizer(3, 1, 0, 0)
+ buttons.Add( (20, 80), 0, wx.EXPAND, 0)
+ retrieve_button = wx.Button(self, ID_DBCHOOSE_RETRIEVE, _("Retrieve"))
+ self.Bind(wx.EVT_BUTTON, self.OnRetrieve, id=ID_DBCHOOSE_RETRIEVE)
+ buttons.Add(retrieve_button, 0, wx.ALL
+ |wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 4)
+ buttons.Add( (20, 80), 0, wx.EXPAND, 0)
+ main_sizer.Add(buttons, 0, wx.EXPAND, 0)
+
+ # The list box with the tables
+ static_box = wx.StaticBoxSizer(wx.StaticBox(self, -1, _("Tables")),
+ wx.HORIZONTAL)
+ self.lb_tables = wx.ListBox(self, ID_LB_DCLICK)
+ self.Bind(wx.EVT_LISTBOX, self.OnTableSelect, id=ID_LB_DCLICK)
+ self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnLBDClick, id=ID_LB_DCLICK)
+ static_box.Add(self.lb_tables, 0, wx.EXPAND, 0)
+ main_sizer.Add(static_box, 1, wx.EXPAND, 0)
+
+ # id column and geometry column selection
+ box = wx.BoxSizer(wx.VERTICAL)
+ box.Add(wx.StaticText(self, -1, _("ID Column")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_id_column = wx.ComboBox(self, -1, "")
+ box.Add(self.text_id_column, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+
+ box.Add(wx.StaticText(self, -1, _("Geometry Column")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_geo_column = wx.ComboBox(self, -1, "")
+ box.Add(self.text_geo_column, 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ main_sizer.Add(box, 1, wx.EXPAND, 0)
+
+ # The standard button box at the bottom of the dialog
+ buttons = wx.FlexGridSizer(1, 2, 0, 0)
+ ok_button = wx.Button(self, ID_DBCHOOSE_OK, _("OK"))
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=ID_DBCHOOSE_OK)
+ buttons.Add(ok_button, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ cancel_button = wx.Button(self, ID_DBCHOOSE_CANCEL, _("Cancel"))
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=ID_DBCHOOSE_CANCEL)
+ buttons.Add(cancel_button, 0, wx.ALL, 4)
+ top.Add(buttons, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 4)
+
+ # Autosizing
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+ self.Layout()
+
+
+ def GetTable(self):
+ i = self.lb_tables.GetSelection()
+ if i >= 0:
+ return (self.selected_conn, self.tables[i],
+ self.text_id_column.GetValue(),
+ self.text_geo_column.GetValue())
+ return None
+
+ def OnRetrieve(self, event):
+ i = self.lb_connections.GetSelection()
+ if i >= 0:
+ self.selected_conn = self.dbconns[i]
+ self.tables = self.selected_conn.GeometryTables()
+ self.lb_tables.Set(self.tables)
+
+ def OnTableSelect(self, event):
+ i = self.lb_tables.GetSelection()
+ self.text_id_column.Clear()
+ self.text_geo_column.Clear()
+ if i >= 0:
+ for name, typ in self.selected_conn.table_columns(self.tables[i]):
+ if typ == "geometry":
+ self.text_geo_column.Append(name)
+ elif typ == FIELDTYPE_INT:
+ self.text_id_column.Append(name)
+
+ def OnLBDClick(self, event):
+ if self.lb_tables.GetSelection() >= 0:
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnOK(self, event):
+ self.EndModal(wx.ID_OK)
+ self.Show(False)
+
+ def OnCancel(self, event):
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+
+class DBDialog(wx.Dialog):
+
+ """Dialog for the parameters of a database connection"""
+
+ def __init__(self, parent, title, parameters, message = ""):
+ """Initialize the dialog box.
+
+ The parameters argument should be a dictionary containing known
+ connection parameters.
+
+ The optional message parameter will be displayed at the top of
+ the dialog box and can be used to display error messages when
+ using the dialog to ask for correct parameters when the
+ connection can't be established.
+ """
+ wx.Dialog.__init__(self, parent, -1, title)
+
+ top = wx.BoxSizer(wx.VERTICAL)
+
+ if message:
+ top.Add(wx.StaticText(self, -1, message), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.StaticText(self, -1, _("Hostname:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_host = wx.TextCtrl(self, -1, parameters.get("host", ""))
+ box.Add(self.text_host, 2, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ box.Add(wx.StaticText(self, -1, _("Port:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_port = wx.TextCtrl(self, -1, parameters.get("port", ""))
+ box.Add(self.text_port, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ top.Add(box, 0, wx.EXPAND)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.StaticText(self, -1, _("Database Name:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_dbname = wx.TextCtrl(self, -1,
+ parameters.get("dbname", ""))
+ box.Add(self.text_dbname, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ top.Add(box, 0, wx.EXPAND)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.StaticText(self, -1, _("User:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_user = wx.TextCtrl(self, -1,
+ parameters.get("user", ""))
+ box.Add(self.text_user, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 4)
+ box.Add(wx.StaticText(self, -1, _("Password:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.text_password = wx.TextCtrl(self, -1,
+ parameters.get("password", ""),
+ style = wx.TE_PASSWORD)
+ box.Add(self.text_password, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND,
+ 4)
+ top.Add(box, 0, wx.EXPAND)
+
+ buttons = wx.BoxSizer(wx.HORIZONTAL)
+ button = wx.Button(self, wx.ID_OK, _("OK"))
+ buttons.Add(button, 0, wx.ALL, 4)
+ button = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
+ buttons.Add(button, 0, wx.ALL, 4)
+ top.Add(buttons, 0, wx.ALIGN_RIGHT, 4)
+
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=wx.ID_CANCEL)
+
+ def RunDialog(self):
+ self.ShowModal()
+ self.Destroy()
+ return self.result
+
+ def end_dialog(self, result):
+ self.result = result
+ if result is not None:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_CANCEL)
+ self.Show(False)
+
+ def OnOK(self, event):
+ result = {}
+ for name in ("host", "port", "dbname", "user", "password"):
+ result[name] = getattr(self, "text_" + name).GetValue()
+ self.end_dialog(result)
+
+ def OnCancel(self, event):
+ self.end_dialog(None)
+
+
+
+class DBFrame(NonModalDialog):
+
+ """Databse connection management dialog"""
+
+ def __init__(self, parent, name, session, *args, **kwds):
+ kwds["style"] = wx.ICONIZE|wx.CAPTION|wx.MINIMIZE
+ NonModalDialog.__init__(self, parent, name, "")
+ self.session = session
+ self.app = self.parent.application
+
+ self.app.Subscribe(SESSION_REPLACED, self.session_replaced)
+ self.subscribe_session()
+
+ self.DB_ListBox = wx.ListBox(self, -1,
+ style=wx.LB_SINGLE|wx.LB_HSCROLL|wx.LB_ALWAYS_SB)
+ self.DB_Add = wx.Button(self, ID_DB_ADD, _("Add"))
+ self.DB_Remove = wx.Button(self, ID_DB_REMOVE, _("Remove"))
+ self.DB_CLOSE = wx.Button(self, wx.ID_CLOSE, _("Close"))
+ self.__set_properties()
+ self.__do_layout()
+ self.Bind(wx.EVT_BUTTON, self.OnAdd, id=ID_DB_ADD)
+ self.Bind(wx.EVT_BUTTON, self.OnRemove, id=ID_DB_REMOVE)
+ self.Bind(wx.EVT_BUTTON, self.OnClose, id=wx.ID_CLOSE)
+
+ self.conns_changed()
+
+ def __set_properties(self):
+ self.SetTitle(_("Database Management"))
+ self.DB_ListBox.SetSize((200, 157))
+
+ def __do_layout(self):
+ top = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+
+ box.Add(self.DB_ListBox, 1, wx.ALL|wx.EXPAND
+ |wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ buttons = wx.BoxSizer(wx.VERTICAL)
+ buttons.Add(self.DB_Add, 0, wx.ALL, 4)
+ buttons.Add(self.DB_Remove, 0, wx.ALL, 4)
+
+ box.Add(buttons, 0, wx.EXPAND)
+ top.Add(box, 1, wx.EXPAND)
+
+ buttons = wx.BoxSizer(wx.HORIZONTAL)
+ buttons.Add(self.DB_CLOSE, 1, wx.ALL|wx.ALIGN_RIGHT, 4)
+ top.Add(buttons, 0, wx.ALIGN_RIGHT)
+
+ self.SetAutoLayout(1)
+ self.SetSizer(top)
+ top.Fit(self)
+ top.SetSizeHints(self)
+
+ def subscribe_session(self):
+ """Internal: Subscribe to some session messages"""
+ self.session.Subscribe(DBCONN_ADDED, self.conns_changed)
+ self.session.Subscribe(DBCONN_REMOVED, self.conns_changed)
+
+ def unsubscribe_session(self):
+ """Internal: Subscribe from messages subscribe in subscribe_session"""
+ self.session.Subscribe(DBCONN_ADDED, self.conns_changed)
+ self.session.Subscribe(DBCONN_REMOVED, self.conns_changed)
+
+ def session_replaced(self, *args):
+ """Internal: resubscribe the session messages
+
+ This method is a subscriber for the application's
+ SESSION_REPLACED messages.
+ """
+ self.unsubscribe_session()
+ self.session = self.app.Session()
+ self.subscribe_session()
+ self.conns_changed()
+
+ def conns_changed(self, *args):
+ """Internal: update the db connection list box
+
+ Subscribed to the DBCONN_ADDED and DBCONN_REMOVED messages.
+ """
+ self.DB_ListBox.Clear()
+ for conn in self.session.DBConnections():
+ self.DB_ListBox.Append(conn.BriefDescription(), conn)
+
+ def OnClose(self, event):
+ self.unsubscribe_session()
+ self.app.Unsubscribe(SESSION_REPLACED, self.session_replaced)
+ NonModalDialog.OnClose(self, event)
+
+ def RunMessageBox(self, title, text, flags = wx.OK | wx.ICON_INFORMATION):
+ """Run a modal message box with the given text, title and flags
+ and return the result"""
+ dlg = wxMessageDialog(self, text, title, flags)
+ dlg.CenterOnParent()
+ result = dlg.ShowModal()
+ dlg.Destroy()
+ return result
+
+ def OnAdd(self, event):
+ message = ""
+ parameters = {}
+ while 1:
+ dialog = DBDialog(self, _("Add Database"), parameters, message)
+ parameters = dialog.RunDialog()
+ if parameters is not None:
+ for conn in self.session.DBConnections():
+ if conn.MatchesParameters(parameters):
+ self.RunMessageBox(_("Add Database"),
+ _("Connection '%s' already exists")
+ % conn.BriefDescription())
+ break
+ else:
+ try:
+ conn = PostGISConnection(**parameters)
+ except ConnectionError, val:
+ message = str(val)
+ else:
+ self.session.AddDBConnection(conn)
+ break
+ else:
+ break
+
+ def OnRemove(self, event):
+ i = self.DB_ListBox.GetSelection()
+ if i >= 0:
+ conn = self.DB_ListBox.GetClientData(i)
+ if self.session.CanRemoveDBConnection(conn):
+ self.session.RemoveDBConnection(conn)
+ else:
+ self.RunMessageBox(_("Remove Database Connection"),
+ _("The connection %s\nis still in use")
+ % conn.BriefDescription())
Added: packages/thuban/branches/upstream/current/Thuban/UI/dialogs.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/dialogs.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/dialogs.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,70 @@
+# Copyright (c) 2001, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Base classes for dialogs"""
+
+__version__ = "$Revision: 2700 $"
+
+import wx
+
+class ThubanFrame(wx.Frame):
+
+ def __init__(self, parent, name, title):
+ wx.Frame.__init__(self, parent, -1, title,
+ style = wx.DEFAULT_FRAME_STYLE )
+ self.parent = parent
+ self.name = name
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+ self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+ def OnClose(self, event):
+ # FIXME: Shouldn't this really be in OnDestroy?
+ if self.parent.dialogs.has_key(self.name):
+ self.parent.remove_dialog(self.name)
+ self.Destroy()
+
+ def OnDestroy(self, event):
+ """Implement in derived classes for resource cleanup, etc."""
+
+
+class NonModalDialog(wx.Dialog):
+ def __init__(self, parent, name, title):
+ wx.Dialog.__init__(self, parent, -1, title,
+ style = wx.DEFAULT_DIALOG_STYLE
+ | wx.SYSTEM_MENU
+ | wx.MINIMIZE_BOX
+ | wx.MAXIMIZE_BOX
+ | wx.RESIZE_BORDER
+ )
+ self.parent = parent
+ self.name = name
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+ def OnClose(self, event):
+ if self.parent.dialogs.has_key(self.name):
+ self.parent.remove_dialog(self.name)
+ self.Destroy()
+
+class NonModalNonParentDialog(wx.Dialog):
+ def __init__(self, parent, name, title):
+ wx.Dialog.__init__(self, None, -1, title,
+ style = wx.DEFAULT_DIALOG_STYLE
+ | wx.SYSTEM_MENU
+ | wx.MINIMIZE_BOX
+ | wx.MAXIMIZE_BOX
+ | wx.RESIZE_BORDER
+ | wx.DIALOG_NO_PARENT
+ )
+ self.parent = parent
+ self.name = name
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+ def OnClose(self, event):
+ if self.parent.dialogs.has_key(self.name):
+ self.parent.remove_dialog(self.name)
+ self.Destroy()
Added: packages/thuban/branches/upstream/current/Thuban/UI/dock.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/dock.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/dock.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,511 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Classes for creating dockable windows.
+
+The DockFrame is the main window that will be the parent for the
+dockable windows.
+
+The DockPanel is a panel that all windows that wish to be dockable
+should derive from.
+"""
+
+__version__ = "$Revision: 2700 $"
+
+import resource
+
+from Thuban import _
+
+import wx
+
+from Thuban.Lib.connector import Publisher
+
+from dialogs import NonModalDialog
+
+from messages import DOCKABLE_DOCKED, DOCKABLE_UNDOCKED, DOCKABLE_CLOSED
+
+ID_BUTTON_DOCK = 4001
+ID_BUTTON_CLOSE = 4002
+
+PANEL_ID = 3141
+
+DOCK_BMP = "dock_12"
+UNDOCK_BMP = "undock_12"
+CLOSE_BMP = "close_12"
+
+class DockPanel(wx.Panel):
+ """A DockPanel is a panel that should be derived from to create panels
+ that can be docked in a DockFrame.
+ """
+
+ def __init__(self, parent, id):
+ """parent should be a DockableWindow created from
+ DockFrame.CreateDock().
+ """
+
+ if not isinstance(parent, DockableWindow):
+ raise TypeError("")
+
+ wx.Panel.__init__(self, parent.GetCurrentParent(), id)
+
+ self.parent = parent
+
+ #self.SetDockParent(None)
+ #parent.SetPanel(self)
+
+ def Create(self):
+ self.parent.SetPanel(self)
+
+ def SetDockParent(self, parent):
+ self.__dockParent = parent
+
+ def GetDockParent(self):
+ return self.__dockParent
+
+ def SetDock(self, dock):
+ """Specifically set the docked state of the panel
+ to dock (True or False).
+ """
+ #if dock == self.IsDocked(): return
+
+ if dock:
+ self.Dock()
+ else:
+ self.UnDock()
+
+ def Dock(self):
+ """Dock the panel in the DockFrame."""
+ self.GetDockParent().Dock()
+
+ def UnDock(self):
+ """Undock the panel in the DockFrame."""
+ self.GetDockParent().UnDock()
+
+ def IsDocked(self):
+ """Return True if the panel is docked."""
+ return self.GetDockParent().IsDocked()
+
+class DockableWindow(Publisher):
+
+ def __getattr__(self, attr):
+ return getattr(self.__topWindow, attr)
+
+ def __init__(self, parent, id, name, title, dockWindow, orient):
+ """Create the dockable window.
+
+ Initially, the window is hidden, but in an undocked state.
+ """
+
+ if not isinstance(parent, DockFrame): raise TypeError("")
+
+ self.__parent = parent
+ self.__id = id
+ self.__name = name
+
+ self.__orientation = orient
+
+ self.__dockWindow = dockWindow
+ self.__floatWindow = wx.Frame(parent, id, title)
+
+ self.__docked = False
+ if self.__docked:
+ self.__topWindow = self.__dockWindow
+ else:
+ self.__topWindow = self.__floatWindow
+
+ self.__floatSize = None
+ self.__floatPosition = None
+
+ self.__dockPanel = None
+ self.__panel = None
+
+ self.__dockWindow.Hide()
+ self.__floatWindow.Hide()
+
+ self.Bind(wx.EVT_CLOSE, self._OnClose)
+
+ ##
+ # Public methods
+ #
+
+ def GetName(self):
+ return self.__name
+
+ def SetPanel(self, panel):
+
+ if not isinstance(panel, DockPanel):
+ raise TypeError("")
+
+ self.__panel = panel
+ self.__panel.SetDockParent(self)
+ self.__CreateBorder()
+
+ self.SetDock(self.__docked)
+
+ def GetPanel(self):
+ return self.__panel
+
+ def GetCurrentParent(self):
+ return self.__topWindow
+
+ def SetDock(self, dock):
+
+ self.__CheckAllGood()
+
+ if dock:
+ self.Dock()
+ else:
+ self.UnDock()
+
+ def Dock(self):
+ """Dock the window."""
+ self.__CheckAllGood()
+
+ wasVisible = self.IsShown()
+
+ if wasVisible: self.Show(False)
+
+ self.__docked = True
+
+ #
+ # save window information
+ #
+ self.__floatSize = self.GetSize()
+ self.__floatPosition = self.GetPosition()
+
+ #
+ # reparent
+ #
+ self.__topWindow = self.__dockWindow
+ self.__dockPanel.Reparent(self.__topWindow)
+
+ self.__dockButton.SetBitmapLabel(self.__bmpUnDock)
+ self.__dockButton.SetBitmapFocus(self.__bmpUnDock)
+ self.__dockButton.SetBitmapSelected(self.__bmpUnDock)
+ self.__dockButton.SetBitmapDisabled(self.__bmpUnDock)
+ self.__dockButton.SetToolTip(wx.ToolTip(_("Undock")))
+
+ self.SetDockSize(self.__dockWindow.GetSize())
+
+ if wasVisible: self.Show(True)
+
+ self.issue(DOCKABLE_DOCKED, self.__id, self)
+
+ def UnDock(self):
+ """Undock the window."""
+ self.__CheckAllGood()
+
+ wasVisible = self.IsShown()
+
+ if wasVisible: self.Show(False)
+
+ self.__docked = False
+
+ #
+ # reparent
+ #
+ self.__topWindow = self.__floatWindow
+ self.__dockPanel.Reparent(self.__topWindow)
+
+ self.__dockButton.SetBitmapLabel(self.__bmpDock)
+ self.__dockButton.SetBitmapFocus(self.__bmpDock)
+ self.__dockButton.SetBitmapSelected(self.__bmpDock)
+ self.__dockButton.SetBitmapDisabled(self.__bmpDock)
+ self.__dockButton.SetToolTip(wx.ToolTip(_("Dock")))
+
+ if wasVisible: self.Show()
+
+ #
+ # restore window information
+ #
+ if self.__floatPosition is not None:
+ self.SetPosition(self.__floatPosition)
+ if self.__floatSize is not None:
+ self.SetSize(self.__floatSize)
+
+ self.__dockPanel.SetSize(self.__topWindow.GetClientSize())
+
+ self.issue(DOCKABLE_UNDOCKED, self.__id, self)
+
+ def IsDocked(self):
+ self.__CheckAllGood()
+ return self.__docked
+
+ def Show(self, show = True):
+ """Show or hide the window."""
+ if show:
+ self.__DoShow()
+ else:
+ self.__DoHide()
+
+ def SetDockSize(self, rect = None):
+ """Set the size of the dock window to rect."""
+
+ w0, h0 = self.__dockPanel.GetBestSize()
+ w, h = self.__panel.GetBestSize()
+
+ if (w, h) < (w0, h0):
+ w = w0
+ h = h0
+
+ if rect is not None:
+ rw = rect.width
+ rh = rect.height
+ if rw < w: rw = w
+ if rh < h: rh = h
+ else:
+ rw = w
+ rh = h
+
+ # these are to account for the border?!!?
+ rw += 8 # XXX: without this the sash isn't visible!?!?!?!
+ rh += 8 # XXX: without this the sash isn't visible!?!?!?!
+
+ self.__dockWindow.SetDefaultSize(wx.Size(rw, rh))
+
+
+ def Destroy(self):
+ self.__panel.Destroy()
+ self.__floatWindow.Destroy()
+ self.__dockWindow.Destroy()
+ self.__parent.OnDockDestroy(self)
+
+ ##
+ # Event handlers
+ #
+
+ def _OnButtonClose(self, event):
+ #self.Close()
+ self.Show(False)
+
+ def _OnClose(self, force = False):
+ self.Show(False)
+
+ def _OnToggleDock(self, event):
+ self.__CheckAllGood()
+
+ self.SetDock(not self.IsDocked())
+
+ ##
+ # Private methods
+ #
+
+ def __CheckAllGood(self):
+ if self.__panel is None:
+ raise TypeError("")
+
+ def __DoShow(self):
+ if self.IsShown(): return
+
+ self.__topWindow.Show()
+
+ if self.__topWindow is self.__dockWindow:
+ self.__parent._UpdateDocks()
+
+ def __DoHide(self):
+ if not self.IsShown(): return
+
+ self.__topWindow.Show(False)
+
+ if self.__topWindow is self.__dockWindow:
+ self.__parent._UpdateDocks()
+
+ def __CreateBorder(self):
+
+ self.__dockPanel = wx.Panel(self.__topWindow, -1, style=wx.SUNKEN_BORDER)
+
+ self.__panel.Reparent(self.__dockPanel)
+ self.__panel.SetId(PANEL_ID)
+
+ if self.__orientation == wx.LAYOUT_VERTICAL:
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ headerBoxOrient = wx.HORIZONTAL
+ else:
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ headerBoxOrient = wx.VERTICAL
+
+
+ headerBox = wx.StaticBoxSizer(
+ wx.StaticBox(self.__dockPanel, -1, ""), headerBoxOrient)
+
+ #
+ # ideally, we should be able to rotate this text depending on
+ # our orientation
+ #
+ text = wx.StaticText(self.__dockPanel, -1, self.GetTitle(),
+ style = wx.ALIGN_CENTRE)
+ font = text.GetFont()
+ font.SetPointSize(10)
+ text.SetFont(font)
+
+ #
+ # load the dock/undock/close bitmaps
+ # and create the buttons
+ #
+ self.__bmpDock = \
+ resource.GetBitmapResource(DOCK_BMP, wx.BITMAP_TYPE_XPM)
+ self.__bmpUnDock = \
+ resource.GetBitmapResource(UNDOCK_BMP, wx.BITMAP_TYPE_XPM)
+
+ if self.__docked:
+ bmp = self.__bmpDock
+ else:
+ bmp = self.__bmpUnDock
+
+ self.__dockButton = wx.BitmapButton(
+ self.__dockPanel, ID_BUTTON_DOCK,
+ bmp,
+ size = wx.Size(bmp.GetWidth() + 4, bmp.GetHeight() + 4),
+ style = wx.BU_EXACTFIT | wx.ADJUST_MINSIZE)
+
+ bmp = resource.GetBitmapResource(CLOSE_BMP, wx.BITMAP_TYPE_XPM)
+
+ closeX = wx.BitmapButton(self.__dockPanel, ID_BUTTON_CLOSE, bmp,
+ size = wx.Size(bmp.GetWidth() + 4,
+ bmp.GetHeight() + 4),
+ style = wx.BU_EXACTFIT | wx.ADJUST_MINSIZE)
+ closeX.SetToolTip(wx.ToolTip(_("Close")))
+
+ #
+ # fill in the sizer in an order appropriate to the orientation
+ #
+ if self.__orientation == wx.LAYOUT_VERTICAL:
+ headerBox.Add(text, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
+ headerBox.Add((1, 5), 1, wx.GROW)
+ headerBox.Add(self.__dockButton, 0, wx.ALIGN_RIGHT, 0)
+ headerBox.Add(closeX, 0, wx.ALIGN_RIGHT | wx.LEFT, 4)
+ else:
+ headerBox.Add(closeX, 0, wx.ALIGN_RIGHT | wx.BOTTOM, 4)
+ headerBox.Add(self.__dockButton, 0, wx.ALIGN_RIGHT, 0)
+ headerBox.Add(text, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTRE_VERTICAL, 0)
+
+ sizer.Add(headerBox, 0, wx.GROW, 0)
+ sizer.Add(self.__panel, 1, wx.GROW, 0)
+
+
+ self.__dockPanel.SetAutoLayout(True)
+ self.__dockPanel.SetSizer(sizer)
+ sizer.SetSizeHints(self.__dockPanel)
+ sizer.SetSizeHints(self.__floatWindow)
+
+ self.Bind(wx.EVT_BUTTON, self._OnToggleDock, self.__dockPanel, id=ID_BUTTON_DOCK)
+ self.Bind(wx.EVT_BUTTON, self._OnButtonClose, self.__dockPanel, id=ID_BUTTON_CLOSE)
+
+
+class DockFrame(wx.Frame):
+ """A DockFrame is a frame that will contain dockable panels."""
+
+ def __init__(self, parent, id, title, position, size):
+ wx.Frame.__init__(self, parent, id, title, position, size)
+
+ self.openWindows = {}
+
+ self.__update_lock = 0
+
+ self.SetMainWindow(None)
+
+
+ self.Bind(wx.EVT_SIZE, self._OnSashSize)
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+ layout2oppSash = {
+ wx.LAYOUT_NONE : wx.SASH_NONE,
+ wx.LAYOUT_TOP : wx.SASH_BOTTOM,
+ wx.LAYOUT_LEFT : wx.SASH_RIGHT,
+ wx.LAYOUT_RIGHT : wx.SASH_LEFT,
+ wx.LAYOUT_BOTTOM : wx.SASH_TOP }
+
+
+ def OnClose(self, event):
+
+ self.__update_lock += 1
+
+ #
+ # child windows are not notified when the parent is destroyed
+ # as of v2.4.0.3 so we need to interate over our children
+ # and tell them to go away.
+ #
+ for key in self.openWindows.keys():
+ win = self.openWindows[key]
+ win.Destroy()
+
+ self.__update_lock -= 1
+
+ # should really call _UpdateDocks() here but we don't need to
+ # since we're going away
+
+ def CreateDock(self, name, id, title, align):
+ """Create a new dock. align specifies where the dock will
+ be placed. It can be one of wxLAYOUT_NONE, wxLAYOUT_LEFT,
+ wxLAYOUT_RIGHT.
+ """
+
+ if align in (wx.LAYOUT_NONE, wx.LAYOUT_LEFT, wx.LAYOUT_RIGHT):
+ orient = wx.LAYOUT_VERTICAL
+ else:
+ orient = wx.LAYOUT_HORIZONTAL
+
+ sash = wx.SashLayoutWindow(self, id, style=wx.NO_BORDER|wx.SW_3D)
+ sash.SetOrientation(orient)
+ sash.SetAlignment(align)
+ sash.SetSashVisible(DockFrame.layout2oppSash[align], True)
+ sash.SetSashBorder(DockFrame.layout2oppSash[align], True)
+
+ win = DockableWindow(self, id, name, title, sash, orient)
+
+ self.__RegisterDock(name, win)
+ self.Bind(wx.EVT_SASH_DRAGGED, self._OnSashDragged, id=id)
+
+ return win
+
+ def FindRegisteredDock(self, name):
+ """Return a reference to a dock that has name."""
+ return self.openWindows.get(name)
+
+ def OnDockDestroy(self, win):
+ del self.openWindows[win.GetName()]
+ self._UpdateDocks()
+
+ def SetMainWindow(self, main):
+ self.__mainWindow = main
+ self._UpdateDocks()
+
+ def _UpdateDocks(self):
+ if self.__update_lock == 0:
+ wx.LayoutAlgorithm().LayoutWindow(self, self.__mainWindow)
+
+ def _OnSashDragged(self, event):
+ if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE:
+ return
+
+ id = event.GetId()
+ sash = self.FindWindowById(id)
+ #assert(isinstance(win, wxPanel))
+ dockPanel = sash.GetChildren()[0]
+ panel = dockPanel.FindWindowById(PANEL_ID)
+ assert isinstance(panel, DockPanel)
+ win = panel.GetDockParent()
+ assert isinstance(win, DockableWindow)
+
+ assert win.IsDocked()
+
+ rect = event.GetDragRect()
+
+ win.SetDockSize(rect)
+
+ self._UpdateDocks()
+
+ def _OnSashSize(self, event):
+ self._UpdateDocks()
+
+ def __RegisterDock(self, name, win):
+ if self.FindRegisteredDock(name) is not None:
+ raise ValueError(
+ "A dockable window is already registered under the name '%s'" % name)
+
+ self.openWindows[name] = win
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/exceptiondialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/exceptiondialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/exceptiondialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,64 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagnber <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+import sys
+
+import wx
+
+from Thuban import _
+
+class ExceptionDialog(wx.Dialog):
+
+ """The exception dialog shows the exception message and then allows
+ to either proceed with the application or to exit it. In the
+ latter case, sys.exit(1) is applied immediately.
+ """
+
+ def __init__(self, parent, message, title = _('Thuban: Internal Error')):
+ wx.Dialog.__init__(self, parent, -1, title,
+ wx.DefaultPosition,
+ style = wx.RESIZE_BORDER|wx.CAPTION|wx.DIALOG_MODAL)
+
+ self.parent = parent
+ self.dialog_layout(message)
+
+ def dialog_layout(self, message):
+ top_box = wx.BoxSizer(wx.VERTICAL)
+
+ textBox = wx.TextCtrl(self, -1, message,
+ style=wx.TE_READONLY|wx.TE_MULTILINE|wx.TE_LINEWRAP)
+ w, h = (500, 300)
+ textBox.SetSizeHints(w, h)
+ textBox.SetSize((w, h))
+
+ top_box.Add(textBox, 1, wx.EXPAND|wx.ALL, 10)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.Button(self, wx.ID_OK, _("Proceed")), 0, wx.ALL, 4)
+ box.Add(wx.Button(self, wx.ID_CANCEL, _("Exit Thuban now")), 0, wx.ALL, 4)
+ top_box.Add(box, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.Bind(wx.EVT_BUTTON, self.OnExit, id=wx.ID_CANCEL)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(top_box)
+ top_box.Fit(self)
+ top_box.SetSizeHints(self)
+
+ def OnOK(self, event):
+ self.EndModal(wx.ID_OK)
+
+ def OnExit(self, event):
+ sys.exit(1)
+
+def run_exception_dialog(parent, message, title = _('Thuban: Internal Error')):
+ dialog = ExceptionDialog(parent, message, title)
+ dialog.ShowModal()
+ dialog.Destroy()
Added: packages/thuban/branches/upstream/current/Thuban/UI/extensionregistry.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/extensionregistry.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/extensionregistry.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,116 @@
+# Copyright (C) 2004, 2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de> (2004, 2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Registry for Extensions.
+
+This module defines a registry for Extensions.
+This is basically used for displaying information on
+the active Extensions in the general About-Dialog.
+A registration is not mandatory to make a Extension
+work, but any Extension should register to provide
+a complete information in the Thuban About Dialog.
+
+A Extension should define a ExtensionDesc object
+and apply ext_registry.add() to register it.
+"""
+
+__version__ = "$Revision: 2580 $"
+# $Source$
+# $Id: extensionregistry.py 2580 2005-03-10 22:39:11Z jan $
+
+from Thuban import _
+
+class ExtensionDesc:
+
+ """
+ A description of a Thuban Extension.
+ """
+
+ def __init__(self, name, version, authors, copyright, desc,
+ init_callback = None):
+ """
+ Initialize a new Thuban Extension information.
+
+ name -- The name of the Thuban Extension.
+ Example: 'gns2shp'
+
+ version -- The version number of the Thuban Extension.
+ Example: '1.0.0'
+
+ authors -- List of authors.
+ Example: [ 'Jan-Oliver Wagner' ]
+
+ copyright -- Copyright notice.
+ Example: '2003, 2004 Intevation GmbH'
+
+ desc -- Short description of the Thuban Extension.
+ Example: _('''
+ Converts GNS (Geographical Name Service of NIMA)
+ to Shapefile format and displays the data.
+ ''')
+ init_callback -- a callback method that is executed if not
+ None. This method should contain gui specific
+ initializations of the extension.
+ Default is None.
+
+ This callback should return None if
+ the intialisation as successful. Else
+ a string describing the problems during
+ intialization.
+ """
+ self.name = name
+ self.version = version
+ self.authors = authors
+ self.copyright = copyright
+ self.desc = desc
+ self.init_callback = init_callback
+ self.status = _("Initialization not yet requested.")
+
+ def init_ext(self):
+ """Execute the init callback for the extension.
+
+ Do nothing if the callback is None.
+
+ It is expected that the callback function returns
+ None if all was OK and a string if something was wrong.
+ The string is believed to describe the problems.
+ """
+ if self.init_callback is not None:
+ result = self.init_callback()
+ if result is not None:
+ self.status = result
+ else:
+ self.status = _("Initialization successful.")
+
+class ExtensionRegistry:
+
+ """
+ A ExtensionRegistry keeps information on the registered
+ Thuban Extensions.
+
+ The registry will raise a exception either when the version
+ required for the Extensions exceeds the version of the currently
+ running Thuban or if the name of a registered extension already
+ is used for registering another extension.
+ """
+
+ def __init__(self):
+ self.registry = []
+
+ def __nonzero__(self):
+ return len(self.registry) <> 0
+
+ def __iter__(self):
+ return iter(self.registry)
+
+ def add(self, ext):
+ self.registry.append(ext)
+
+
+# The central Thuban Extensions registry
+ext_registry = ExtensionRegistry()
Added: packages/thuban/branches/upstream/current/Thuban/UI/hittest.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/hittest.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/hittest.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,88 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Martin Mueller <mmueller at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Hit testing functions"""
+
+__version__ = "$Revision: 1589 $"
+# $Source$
+# $Id: hittest.py 1589 2003-08-15 12:49:08Z bh $
+
+from math import hypot, sqrt
+
+def line_hit(sx, sy, ex, ey, px, py):
+ """Determine whether the line fom (SX, SY) to (EX, EY) is `hit' by a
+ click at (PX, PY), or whether a polygon containing this line is hit
+ in the interior at (PX, PY).
+
+ Return -1 if the line it self his hit. Otherwise, return +1 if a
+ horizontal line from (PX, PY) to (-Infinity, PY) intersects the line
+ and 0 if it doesn't.
+
+ The nonnegative return values can be used to determine whether (PX, PY)
+ is an interior point of a polygon according to the even-odd rule.
+ """
+
+ if (ey < sy):
+ sx, ex = ex, sx
+ sy, ey = ey, sy
+
+ not_horizontal = ey > sy + 2
+ if not_horizontal and (py >= ey or py < sy):
+ return 0
+
+ vx = ex - sx
+ vy = ey - sy
+
+ len = sqrt(vx * vx + vy * vy)
+ if not len:
+ # degenerate case of coincident end points. Assumes that some
+ # other part of the code has already determined whether the end
+ # point is hit.
+ return 0
+
+ dx = px - sx
+ dy = py - sy
+ dist = vx * dy - vy * dx
+
+ if ((not_horizontal or (px >= sx and px <= ex) or (px >= ex and px <= sx))
+ and abs(dist) <= (len * 2)):
+ return -1
+
+ # horizontal lines (vy == 0) always return 0 here.
+ return vy and py < ey and py >= sy and dx * abs(vy) > vx * abs(dy)
+
+
+def polygon_hit(points, x, y):
+ """Return whether x, y is in the polygon or on or near the boundary
+
+ The return value is -1 if the point (x, y) is near the boundary, 1
+ if the point is inside and 0 if it's outside.
+
+ The points argument should be a list of lists of coordinate pairs.
+ """
+ crossings = 0
+ for ring in points:
+ for i in range(len(ring) - 1):
+ sx, sy = ring[i]
+ ex, ey = ring[i + 1]
+ hit = line_hit(sx, sy, ex, ey, x, y)
+ if hit < 0:
+ return hit
+ crossings += hit
+ return crossings % 2
+
+
+def arc_hit(points, x, y):
+ """Return whether x, y is on or near the arc's boundary
+
+ The return value is -1 if the point (x, y) is near the boundary, 1
+ if the point is inside and 0 if it's outside.
+
+ The points argument should be a list of lists of coordinate pairs.
+ """
+ return polygon_hit(points, x, y) < 0
Added: packages/thuban/branches/upstream/current/Thuban/UI/identifyview.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/identifyview.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/identifyview.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,92 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+import wx
+from wx import grid
+
+from Thuban import _
+
+from dialogs import NonModalDialog
+from controls import RecordListCtrl, RecordGridCtrl
+from messages import SHAPES_SELECTED
+import main
+
+class IdentifyListCtrl(RecordListCtrl):
+
+ def selected_shape(self, layer, shape):
+ if layer is not None:
+ table = layer.ShapeStore().Table()
+ else:
+ table = None
+ self.fill_list(table, shape)
+
+class IdentifyGridCtrl(RecordGridCtrl):
+
+ def selected_shape(self, layer, shape):
+ if layer is not None:
+ table = layer.ShapeStore().Table()
+ else:
+ table = None
+ self.SetTableRecord(table, shape)
+
+class IdentifyView(NonModalDialog):
+
+ ID_STOP = 100
+
+ def __init__(self, parent, name):
+ NonModalDialog.__init__(self, parent, name, _("Identify Shape"))
+ parent.Subscribe(SHAPES_SELECTED, self.selected_shape)
+
+ top_box = wx.BoxSizer(wx.VERTICAL)
+ if main.options.attribute_editing_enabled:
+ self.list = IdentifyGridCtrl(self)
+ else:
+ self.list = IdentifyListCtrl(self, -1)
+ self.list.SetSize(wx.Size(305,200))
+ top_box.Add(self.list, 1, wx.EXPAND|wx.ALL, 4)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.Button(self, wx.ID_CLOSE, _("Close Window")), 0, wx.ALL, 4)
+ box.Add(wx.Button(self, self.ID_STOP, _("Stop Identify Mode")),
+ 0, wx.ALL, 4)
+ top_box.Add(box, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 4)
+
+ self.Bind(wx.EVT_BUTTON, self.OnClose, id=wx.ID_CLOSE)
+ self.Bind(wx.EVT_BUTTON, self.OnStop, id=self.ID_STOP)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(top_box)
+ top_box.Fit(self)
+ top_box.SetSizeHints(self)
+
+ # Make sure to reflect the current selection.
+ self.selected_shape(parent.SelectedLayer(), parent.SelectedShapes())
+
+ def OnClose(self, event):
+ self.parent.Unsubscribe(SHAPES_SELECTED, self.selected_shape)
+ NonModalDialog.OnClose(self, event)
+
+ def OnStop(self, event):
+ self.parent.Unsubscribe(SHAPES_SELECTED, self.selected_shape)
+ self.parent.canvas.SelectTool(None)
+ NonModalDialog.OnClose(self, event)
+
+ def selected_shape(self, layer, shapes):
+ """Subscribed to the SHAPES_SELECTED messages.
+
+ If exactly one shape is selected, pass that shape id to the
+ list's selected_shape method. Otherwise pass None as the shape
+ id.
+ """
+ if len(shapes) == 1:
+ shape = shapes[0]
+ else:
+ shape = None
+ self.list.selected_shape(layer, shape)
Added: packages/thuban/branches/upstream/current/Thuban/UI/join.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/join.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/join.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,246 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""The layer and table join dialog"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: join.py 2700 2006-09-18 14:27:02Z dpinte $
+
+
+import sys
+import wx
+
+from Thuban import _
+
+from Thuban.Model.transientdb import TransientJoinedTable
+from Thuban.Model.data import DerivedShapeStore
+from Thuban.UI.tableview import QueryTableFrame
+
+from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+
+ID_LEFT_TABLE = 4001
+ID_RIGHT_TABLE = 4002
+
+CHOICE_WIDTH = 150
+
+class JoinDialog(wx.Dialog):
+
+ """Table join dialog.
+
+ Join two tables (left/right) based on the user selected fields.
+ Opens a QueryTableFrame and registers the new table with the session.
+ """
+
+ def __init__(self, parent, title, session, layer = None):
+ wx.Dialog.__init__(self, parent, -1, title,
+ style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
+ self.layer = layer
+
+ if not layer:
+ self.choice_left_table = wx.Choice(self, ID_LEFT_TABLE)
+ width, height = self.choice_left_table.GetSizeTuple()
+ self.choice_left_table.SetSize(wx.Size(CHOICE_WIDTH, height))
+ self.left_table = None
+ else:
+ self.choice_left_table = None
+ self.left_table = layer.ShapeStore().Table()
+
+ self.choice_right_table = wx.Choice(self, ID_RIGHT_TABLE)
+ width, height = self.choice_right_table.GetSizeTuple()
+ self.choice_right_table.SetSize(wx.Size(CHOICE_WIDTH, height))
+
+ self.choice_left_field = wx.Choice(self, -1)
+ width, height = self.choice_left_field.GetSizeTuple()
+ self.choice_left_field.SetSize(wx.Size(CHOICE_WIDTH, height))
+ self.choice_right_field = wx.Choice(self, -1)
+ width, height = self.choice_right_field.GetSizeTuple()
+ self.choice_right_field.SetSize(wx.Size(CHOICE_WIDTH, height))
+
+ self.button_join = wx.Button(self, wx.ID_OK, _("Join"))
+ self.button_join.SetDefault()
+ self.button_close = wx.Button(self, wx.ID_CANCEL, _("Close"))
+
+ self.Bind(wx.EVT_BUTTON, self.OnJoin, id=wx.ID_OK)
+
+ if self.choice_left_table is not None:
+ self.choice_left_table.Append(_('Select...'), None)
+ self.choice_right_table.Append(_('Select...'), None)
+
+ for t in session.Tables():
+ if self.choice_left_table is not None:
+ self.choice_left_table.Append(t.Title(), t)
+
+ # If there is no choice_left_table then self.left_table will
+ # be the keft table so we can simply leave it out on the
+ # right side.
+ if t is not self.left_table:
+ self.choice_right_table.Append(t.Title(), t)
+
+ if self.choice_left_table is None:
+ for col in self.left_table.Columns():
+ self.choice_left_field.Append(col.name, col)
+
+ if self.choice_left_table is not None:
+ self.Bind(wx.EVT_CHOICE, self.OnLeftTable, id=ID_LEFT_TABLE)
+ self.Bind(wx.EVT_CHOICE, self.OnRightTable, id=ID_RIGHT_TABLE)
+
+ if self.choice_left_table is not None:
+ self.choice_left_table.SetSelection(0)
+ self.choice_right_table.SetSelection(0)
+ self.button_join.Enable(False)
+
+ topBox = wx.BoxSizer(wx.VERTICAL)
+
+ sizer = wx.FlexGridSizer(2, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Table:")), 0, wx.ALL, 4)
+ if self.choice_left_table is not None:
+ sizer.Add(self.choice_left_table, 1,
+ wx.EXPAND|wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ else:
+ sizer.Add(wx.StaticText(self, -1, self.left_table.Title()), 0,
+ wx.ALL, 4)
+
+ sizer.Add(wx.StaticText(self, -1, _("Table:")), 0, wx.ALL, 4)
+ sizer.Add(self.choice_right_table, 1,
+ wx.EXPAND|wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Field:")), 0, wx.ALL, 4)
+ sizer.Add(self.choice_left_field, 1,
+ wx.EXPAND|wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Field:")), 0, wx.ALL, 4)
+ sizer.Add(self.choice_right_field, 1,
+ wx.EXPAND|wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ sizer.AddGrowableCol(1)
+ sizer.AddGrowableCol(3)
+
+ topBox.Add(sizer, 0, wx.EXPAND|wx.ALL, 4)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.check_outer_join = wx.CheckBox(self,-1,
+ _("Outer Join (preserves left table records)"))
+ sizer.Add(self.check_outer_join, 1, wx.ALL,4)
+ topBox.Add(sizer, 0, wx.ALIGN_LEFT|wx.ALIGN_TOP, 4)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(self.button_join, 0, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.RIGHT,
+ 10)
+ sizer.Add(self.button_close, 0, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.RIGHT,
+ 10)
+
+ topBox.Add(sizer, 1, wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM|wx.BOTTOM|wx.TOP, 10)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(topBox)
+ topBox.Fit(self)
+ topBox.SetSizeHints(self)
+
+ # Save same parameters for later use.
+ self.parent = parent
+ self.session = session
+
+ def OnJoin(self, event):
+ """Get the table and field selections and perform the join."""
+ ThubanBeginBusyCursor()
+ try:
+ # left
+ if self.choice_left_table is not None:
+ i = self.choice_left_table.GetSelection()
+ left_table = self.choice_left_table.GetClientData(i)
+ else:
+ left_table = self.left_table
+ i = self.choice_left_field.GetSelection()
+ left_field = self.choice_left_field.GetString(i)
+ # right
+ i = self.choice_right_table.GetSelection()
+ right_table = self.choice_right_table.GetClientData(i)
+ i = self.choice_right_field.GetSelection()
+ right_field = self.choice_right_field.GetString(i)
+
+ outer_join = self.check_outer_join.IsChecked()
+
+ try:
+ joined_table = TransientJoinedTable(self.session.TransientDB(),
+ left_table, left_field,
+ right_table, right_field,
+ outer_join)
+ except:
+ dlg = wx.MessageDialog(None,
+ _('Join failed:\n %s') % sys.exc_info()[1],
+ _('Info'), wx.OK|wx.ICON_ERROR)
+ dlg.ShowModal()
+ dlg.Destroy()
+ return
+
+ joined_table = self.session.AddTable(joined_table)
+
+ if self.layer is not None:
+ needed_rows = self.layer.ShapeStore().Table().NumRows()
+ joined_rows = joined_table.NumRows()
+ if needed_rows == joined_rows:
+ store = DerivedShapeStore(self.layer.ShapeStore(),
+ joined_table)
+ self.session.AddShapeStore(store)
+ self.layer.SetShapeStore(store)
+
+ finally:
+ ThubanEndBusyCursor()
+
+ if self.layer is not None:
+ if needed_rows != joined_rows:
+ msg = _("The joined table has %(joined)d rows but"
+ " it must have %(needed)d rows"
+ " to be used with the selected layer") \
+ % {"joined": joined_rows,
+ "needed": needed_rows}
+ dlg = wx.MessageDialog(None, msg, _('Join Failed'),
+ wx.OK|wx.ICON_ERROR)
+ dlg.ShowModal()
+ dlg.Destroy()
+ return
+
+ else:
+ name = joined_table.tablename
+ dialog = QueryTableFrame(self.parent, name,
+ _('Table: %s') % joined_table.Title(),
+ joined_table)
+ self.parent.add_dialog(name, dialog)
+ dialog.Show(True)
+
+ self.Close()
+
+ def OnClose(self, event):
+ """Close the dialog."""
+ self.Close()
+
+ def OnLeftTable(self, event):
+ """Get the selected table and fill the field choice."""
+ i = self.choice_left_table.GetSelection()
+ table = self.choice_left_table.GetClientData(i)
+ self.choice_left_field.Clear()
+ if table is not None:
+ for col in table.Columns():
+ self.choice_left_field.Append(col.name, col)
+ self.update_sensitivity()
+
+ def OnRightTable(self, event):
+ """Get the selected table and fill the field choice."""
+ i = self.choice_right_table.GetSelection()
+ table = self.choice_right_table.GetClientData(i)
+ self.choice_right_field.Clear()
+ if table is not None:
+ for col in table.Columns():
+ self.choice_right_field.Append(col.name, col)
+ self.update_sensitivity()
+
+ def update_sensitivity(self):
+ if self.choice_left_table is not None:
+ lsel = self.choice_left_table.GetSelection()
+ else:
+ lsel = sys.maxint
+ sel = self.choice_right_table.GetSelection()
+ self.button_join.Enable(sel > 0 and lsel > 0 and sel != lsel)
Added: packages/thuban/branches/upstream/current/Thuban/UI/labeldialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/labeldialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/labeldialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,73 @@
+# Copyright (c) 2001 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+import wx
+
+from Thuban import _
+
+from controls import SelectableRecordListCtrl
+
+class LabelListCtrl(SelectableRecordListCtrl):
+
+ def __init__(self, parent, id, table, shape):
+ SelectableRecordListCtrl.__init__(self, parent, id)
+ self.fill_list(table, shape)
+
+
+class LabelDialog(wx.Dialog):
+
+ def __init__(self, parent, table, shape_index):
+ wx.Dialog.__init__(self, parent, -1, _("Label Values"),
+ wx.DefaultPosition,
+ style = wx.RESIZE_BORDER|wx.CAPTION|wx.DIALOG_MODAL)
+
+ self.parent = parent
+ self.dialog_layout(table, shape_index)
+
+ def dialog_layout(self, table, shape_index):
+ top_box = wx.BoxSizer(wx.VERTICAL)
+
+ self.list = LabelListCtrl(self, -1, table, shape_index)
+ self.list.SetSize(wx.Size(305,200))
+ top_box.Add(self.list, 1, wx.EXPAND|wx.ALL, 4)
+
+ box = wx.BoxSizer(wx.HORIZONTAL)
+ box.Add(wx.Button(self, wx.ID_OK, _("OK")), 0, wx.ALL, 4)
+ box.Add(wx.Button(self, wx.ID_CANCEL, _("Cancel")), 0, wx.ALL, 4)
+ top_box.Add(box, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=wx.ID_CANCEL)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(top_box)
+ top_box.Fit(self)
+ top_box.SetSizeHints(self)
+
+ def OnOK(self, event):
+ result = self.list.GetValue()
+ if result is not None:
+ self.end_dialog(wx.ID_OK, str(result))
+ else:
+ self.end_dialog(wx.ID_CANCEL, None)
+
+ def OnCancel(self, event):
+ self.end_dialog(wx.ID_CANCEL, None)
+
+ def end_dialog(self, wx_result, result):
+ self.result = result
+ self.EndModal(wx_result)
+
+def run_label_dialog(parent, table, shape_index):
+ dialog = LabelDialog(parent, table, shape_index)
+ if dialog.ShowModal() == wx.ID_OK:
+ return dialog.result
+ else:
+ return None
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/layerproperties.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/layerproperties.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/layerproperties.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,168 @@
+# Copyright (c) 2005 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Base class for Layer Properties dialogs"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: layerproperties.py 2700 2006-09-18 14:27:02Z dpinte $
+
+from Thuban import _
+
+import wx
+from Thuban.Model.messages import MAP_LAYERS_REMOVED, LAYER_SHAPESTORE_REPLACED
+from dialogs import NonModalNonParentDialog
+from messages import MAP_REPLACED
+
+ID_PROPERTY_REVERT = 4002
+ID_PROPERTY_TRY = 4008
+ID_PROPERTY_TITLE = 4012
+
+class LayerProperties(NonModalNonParentDialog):
+
+ def __init__(self, parent, name, layer):
+
+ NonModalNonParentDialog.__init__(self, parent, name, "")
+
+ self.SetTitle(layer.Title())
+
+ self.parent.Subscribe(MAP_REPLACED, self.map_replaced)
+ self.layer = layer
+ self.map = parent.Map()
+
+ self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
+
+ self.layout_recurse = False
+
+ def dialog_layout(self, *args, **kw):
+
+ if self.layout_recurse: return
+ self.layout_recurse = True
+
+ panel = wx.Panel(self, -1)
+
+ topBox = wx.BoxSizer(wx.VERTICAL)
+ panelBox = wx.BoxSizer(wx.VERTICAL)
+
+ # Title
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(wx.StaticText(panel, -1, _("Title: ")),
+ 0, wx.ALIGN_LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 4)
+
+ text_title = wx.TextCtrl(panel, ID_PROPERTY_TITLE, self.layer.Title())
+ text_title.SetInsertionPointEnd()
+ sizer.Add(text_title, 1, wx.GROW | wx.RIGHT, 0)
+
+ panelBox.Add(sizer, 0, wx.GROW | wx.ALL, 4)
+
+ # Type
+ panelBox.Add(wx.StaticText(panel, -1,
+ _("Layer Type: %s") % self.layer.Type()),
+ 0, wx.ALIGN_LEFT | wx.ALL, 4)
+
+ # Projection
+ proj = self.layer.GetProjection()
+ if proj is None:
+ text = _("Projection: None")
+ else:
+ text = _("Projection: %s") % proj.Label()
+
+ panelBox.Add(wx.StaticText(panel, -1, text), 0, wx.ALIGN_LEFT | wx.ALL, 4)
+
+ self.dialog_layout(panel, panelBox)
+
+ button_try = wx.Button(self, ID_PROPERTY_TRY, _("Try"))
+ button_revert = wx.Button(self, ID_PROPERTY_REVERT, _("Revert"))
+ button_ok = wx.Button(self, wx.ID_OK, _("OK"))
+ button_close = wx.Button(self, wx.ID_CANCEL, _("Close"))
+ button_ok.SetDefault()
+
+ buttonBox = wx.BoxSizer(wx.HORIZONTAL)
+ buttonBox.Add(button_try, 0, wx.RIGHT|wx.EXPAND, 10)
+ buttonBox.Add(button_revert, 0, wx.RIGHT|wx.EXPAND, 10)
+ buttonBox.Add(button_ok, 0, wx.RIGHT|wx.EXPAND, 10)
+ buttonBox.Add(button_close, 0, wx.RIGHT|wx.EXPAND, 0)
+
+ panel.SetAutoLayout(True)
+ panel.SetSizer(panelBox)
+ panelBox.Fit(panel)
+ panelBox.SetSizeHints(panel)
+
+ topBox.Add(panel, 1, wx.GROW | wx.ALL, 4)
+ topBox.Add(buttonBox, 0, wx.ALIGN_RIGHT|wx.ALL, 10)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(topBox)
+ topBox.Fit(self)
+ topBox.SetSizeHints(self)
+ self.Layout()
+
+ ###########
+
+ self.Bind(wx.EVT_TEXT, self.OnTitleChanged, id=ID_PROPERTY_TITLE)
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.Bind(wx.EVT_BUTTON, self.OnTry, id=ID_PROPERTY_TRY)
+ self.Bind(wx.EVT_BUTTON, self.OnCloseBtn, id=wx.ID_CANCEL)
+ self.Bind(wx.EVT_BUTTON, self.OnRevert, id=ID_PROPERTY_REVERT)
+
+ ######################
+
+ text_title.SetFocus()
+ self.haveApplied = False
+
+
+ def unsubscribe_messages(self):
+ """Unsubscribe from all messages."""
+ self.parent.Unsubscribe(MAP_REPLACED, self.map_replaced)
+ self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
+
+ def map_layers_removed(self):
+ """Subscribed to MAP_LAYERS_REMOVED. If this layer was removed,
+ Close self.
+ """
+ if self.layer not in self.map.Layers():
+ self.Close()
+
+ def map_replaced(self, *args):
+ """Subscribed to the mainwindow's MAP_REPLACED message. Close self."""
+ self.Close()
+
+ def OnTry(self, event):
+ return
+
+ def OnOK(self, event):
+ self.Close()
+
+ def OnClose(self, event):
+ self.unsubscribe_messages()
+ NonModalNonParentDialog.OnClose(self, event)
+
+ def OnCloseBtn(self, event):
+ """Close is similar to Cancel except that any changes that were
+ made and applied remain applied.
+ """
+
+ self.Close()
+
+ def OnRevert(self, event):
+ return
+
+ def SetTitle(self, title):
+ """Set the title of the dialog."""
+ if title != "":
+ title = ": " + title
+
+ NonModalNonParentDialog.SetTitle(self, _("Layer Properties") + title)
+
+ def OnTitleChanged(self, event):
+ """Update the dialog title when the user changed the layer name."""
+ obj = event.GetEventObject()
+
+ self.layer.SetTitle(obj.GetValue())
+ self.SetTitle(self.layer.Title())
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/legend.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/legend.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/legend.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,788 @@
+# Copyright (c) 2001, 2002, 2003, 2005 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+from math import fabs, cos, pi
+
+from Thuban import _
+
+import resource
+
+import wx
+
+from Thuban.Model.layer import BaseLayer
+from Thuban.Model.map import Map
+from Thuban.Model.classification import ClassGroup
+from Thuban.Model.proj import PROJ_UNITS_DEGREES
+
+from Thuban.Model.messages import \
+ MAP_STACKING_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED, LAYER_CHANGED,\
+ LAYER_VISIBILITY_CHANGED, TITLE_CHANGED
+
+from Thuban.UI.messages import SCALE_CHANGED
+
+from Thuban.UI.classifier import ClassDataPreviewer
+from Thuban.UI.dock import DockPanel
+from Thuban.UI.scalebar import ScaleBar
+
+from Thuban.UI.menu import Menu
+
+from Thuban.Lib.connector import ConnectorError
+
+ID_LEGEND_TOP = 4001
+ID_LEGEND_RAISE = 4002
+ID_LEGEND_LOWER = 4003
+ID_LEGEND_BOTTOM = 4004
+ID_LEGEND_TREE = 4005
+ID_LEGEND_PROPS = 4006
+ID_LEGEND_SHOWLAYER = 4007
+ID_LEGEND_HIDELAYER = 4008
+
+BMP_SIZE_W = 16
+BMP_SIZE_H = 16
+
+TOP_BMP = "top_layer"
+RAISE_BMP = "raise_layer"
+LOWER_BMP = "lower_layer"
+BOTTOM_BMP = "bottom_layer"
+SHOW_BMP = "show_layer"
+HIDE_BMP = "hide_layer"
+PROPS_BMP = "layer_properties"
+
+class LegendPanel(DockPanel):
+
+ def __init__(self, parent, map, mainWindow):
+ DockPanel.__init__(self, parent, -1)
+
+ self.mainWindow = mainWindow
+ self.parent = parent
+
+ self.buttons = []
+
+ panelBox = wx.BoxSizer(wx.VERTICAL)
+
+ self.toolBar = wx.ToolBar(self, -1)
+ self.toolBar.SetToolBitmapSize(wx.Size(24, 24))
+
+ bmp = resource.GetBitmapResource(TOP_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_TOP, bmp,
+ shortHelpString=_("Top Layer"))
+
+ bmp = resource.GetBitmapResource(RAISE_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_RAISE, bmp,
+ shortHelpString=_("Raise Layer"))
+
+ bmp = resource.GetBitmapResource(LOWER_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_LOWER, bmp,
+ shortHelpString=_("Lower Layer"))
+
+ bmp = resource.GetBitmapResource(BOTTOM_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_BOTTOM, bmp,
+ shortHelpString=_("Bottom Layer"))
+
+ bmp = resource.GetBitmapResource(SHOW_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_SHOWLAYER, bmp,
+ shortHelpString=_("Show Layer"))
+
+ bmp = resource.GetBitmapResource(HIDE_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_HIDELAYER, bmp,
+ shortHelpString=_("Hide Layer"))
+
+ bmp = resource.GetBitmapResource(PROPS_BMP, wx.BITMAP_TYPE_XPM)
+ self.toolBar.AddTool(ID_LEGEND_PROPS, bmp,
+ shortHelpString=_("Edit Layer Properties"))
+
+ self.toolBar.Realize()
+ panelBox.Add(self.toolBar, 0, wx.GROW, 0)
+
+ self.Bind(wx.EVT_TOOL, self._OnMoveTop, id=ID_LEGEND_TOP)
+ self.Bind(wx.EVT_TOOL, self._OnMoveUp, id=ID_LEGEND_RAISE)
+ self.Bind(wx.EVT_TOOL, self._OnMoveDown, id=ID_LEGEND_LOWER)
+ self.Bind(wx.EVT_TOOL, self._OnMoveBottom, id=ID_LEGEND_BOTTOM)
+ self.Bind(wx.EVT_TOOL, self._OnProperties, id=ID_LEGEND_PROPS)
+ self.Bind(wx.EVT_TOOL, self._OnShowLayer, id=ID_LEGEND_SHOWLAYER)
+ self.Bind(wx.EVT_TOOL, self._OnHideLayer, id=ID_LEGEND_HIDELAYER)
+
+ self.tree = LegendTree(self, ID_LEGEND_TREE, map, mainWindow)
+
+ panelBox.Add(self.tree, 1, wx.GROW, 0)
+
+ self.scalebarbitmap = ScaleBarBitmap(self, map, mainWindow)
+ panelBox.Add(self.scalebarbitmap, 0, wx.GROW, 0)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(panelBox)
+ panelBox.SetSizeHints(self)
+
+
+ self.panelBox = panelBox
+
+ self.__EnableButtons(False)
+
+ self.Create()
+
+ self.Bind(wx.EVT_CLOSE, self._OnClose)
+
+
+ def GetMap(self):
+ return self.tree.GetMap()
+
+ def SetMap(self, map):
+ self.tree.SetMap(map)
+ self.scalebarbitmap.SetCanvas(self.mainWindow.canvas)
+
+ def DoOnSelChanged(self, layer, group):
+
+ ok = isinstance(layer, BaseLayer)
+ self.__EnableButtons(ok)
+
+ self.mainWindow.SelectLayer(layer)
+
+ def DoOnProperties(self):
+ list = self.tree.GetSelectedHierarchy()
+
+ ok = isinstance(list[0], BaseLayer)
+ if ok:
+ self.mainWindow.OpenLayerProperties(list[0], list[1])
+
+ def Destroy(self):
+ self.__Close()
+
+ def _OnProperties(self, event):
+ self.DoOnProperties()
+
+ def _OnMoveTop(self, event):
+ self.tree.MoveCurrentItemTop()
+
+ def _OnMoveUp(self, event):
+ self.tree.MoveCurrentItemUp()
+
+ def _OnMoveDown(self, event):
+ self.tree.MoveCurrentItemDown()
+
+ def _OnMoveBottom(self, event):
+ self.tree.MoveCurrentItemBottom()
+
+ def _OnShowLayer(self, event):
+ self.tree.DoOnShowLayer()
+ pass
+
+ #def Close(self, force = False):
+ #DockPanel.Close(self, force)
+
+ def _OnClose(self, event):
+ self.__Close()
+
+ def _OnHideLayer(self, event):
+ self.tree.DoOnHideLayer()
+ pass
+
+ def _OnToggleVisibility(self, event):
+ self.tree.ToggleVisibility()
+
+ def _OnProjection(self, event):
+ self.tree.LayerProjection()
+
+ def _OnRemoveLayer(self, event):
+ self.mainWindow.RemoveLayer()
+
+ def _OnShowTable(self, event):
+ self.mainWindow.LayerShowTable()
+
+ def __EnableButtons(self, on):
+ self.toolBar.EnableTool(ID_LEGEND_TOP, on)
+ self.toolBar.EnableTool(ID_LEGEND_RAISE, on)
+ self.toolBar.EnableTool(ID_LEGEND_LOWER, on)
+ self.toolBar.EnableTool(ID_LEGEND_BOTTOM, on)
+ self.toolBar.EnableTool(ID_LEGEND_SHOWLAYER, on)
+ self.toolBar.EnableTool(ID_LEGEND_HIDELAYER, on)
+ self.toolBar.EnableTool(ID_LEGEND_PROPS, on)
+
+ def __Close(self):
+ self.tree.Close()
+
+class LegendTree(wx.TreeCtrl):
+
+ def __init__(self, parent, id, map, mainWindow):
+ wx.TreeCtrl.__init__(self, parent, id,
+ style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT,
+ size = (200, 200))
+
+ self.mainWindow = mainWindow
+ self.map = None
+ self.parent = parent
+ self.changing_selection = 0
+
+ #
+ # The image list used by the wxTreeCtrl causes problems when
+ # we remove layers and/or change a classification because it
+ # changes the image indices if you remove images from the list.
+ # Rather than removing unused images we use this list to keep
+ # track of which indices are available in the image list
+ # (because of a previous removal) and then replace those indices
+ # with new images rather than appending to the end of the image
+ # list (assuming there are any that are available).
+ #
+ self.availImgListIndices = []
+
+ self.image_list = None
+ self.emptyImageIndex = 0
+
+ self.previewer = ClassDataPreviewer()
+
+ self.preventExpandCollapse = False
+ self.raiseProperties = False
+
+ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self._OnItemActivated, id=ID_LEGEND_TREE)
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self._OnSelChanged, id=ID_LEGEND_TREE)
+ self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpandCollapse, id=ID_LEGEND_TREE)
+ self.Bind(wx.EVT_TREE_ITEM_COLLAPSING, self.OnItemExpandCollapse, id=ID_LEGEND_TREE)
+ self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self._OnRightClick, id=ID_LEGEND_TREE)
+
+ self.Bind(wx.EVT_CLOSE, self._OnClose)
+
+ self.SetMap(map)
+
+ def _OnRightClick(self, event):
+ """Select item and pop up a context menu"""
+
+ # The pop up menu is related to the legend tree, so we have direct
+ # access on the tree items. The events issued by the menu are handled
+ # by the legend panel, since most of the handlers are already
+ # implemented there.
+
+ # Update item selection to the right click
+ item = event.GetItem()
+ self.SelectItem(item)
+
+ # Define the menu
+ popup_menu = Menu("PopUp", "",
+ [ "layer_visibility",
+ None,
+ "layer_properties",
+ "layer_projection",
+ "layer_remove",
+ "layer_show_table",
+ None,
+ "layer_to_top",
+ "layer_raise",
+ "layer_lower",
+ "layer_to_bottom"
+ ])
+
+ # Display the menu
+ pos = event.GetPoint()
+ shift = self.ClientToScreen((0,0))
+ self.PopupMenu(self.mainWindow.build_menu(popup_menu), pos)
+
+ def find_layer(self, layer):
+ """Return the tree item for the layer"""
+ root = self.GetRootItem()
+ id, cookie = self.GetFirstChild(root)
+ while id.IsOk():
+ if self.GetPyData(id) is layer:
+ return id
+ id, cookie = self.GetNextChild(root, cookie)
+ return None
+
+ def _OnClose(self, event):
+ self.SetMap(None)
+
+ def GetMap(self):
+ return self.map
+
+ def SetMap(self, map):
+
+ sub_list = [(MAP_STACKING_CHANGED, self._OnMsgMapStackingChanged),
+ (MAP_LAYERS_ADDED, self._OnMsgMapLayersAdded),
+ (MAP_LAYERS_REMOVED, self._OnMsgMapLayersRemoved)]
+
+ if self.map is not None:
+ for msg, func in sub_list: self.map.Unsubscribe(msg, func)
+ #self.mainWindow.application.Unsubscribe(SESSION_REPLACED,
+ #self._OnMsgMapsChanged)
+ #try:
+ #self.mainWindow.application.session.Unsubscribe(MAPS_CHANGED,
+ #self._OnMsgMapsChanged)
+ #except ConnectorError:
+ #pass
+ self.DeleteAllItems()
+
+ self.map = map
+
+ if self.map is not None:
+ for msg, func in sub_list: self.map.Subscribe(msg, func)
+ #self.mainWindow.application.session.Subscribe(MAPS_CHANGED,
+ #self._OnMsgMapsChanged)
+ #self.mainWindow.application.Subscribe(SESSION_REPLACED,
+ #self._OnMsgMapsChanged)
+ self.__FillTree(self.map)
+
+ def MoveCurrentItemTop(self):
+ layer, group = self.GetSelectedHierarchy()
+
+ if layer is not None:
+ self.map.MoveLayerToTop(layer)
+ else:
+ assert False, "Shouldn't be allowed."
+ pass
+
+ def MoveCurrentItemUp(self):
+ layer, group = self.GetSelectedHierarchy()
+
+ if layer is not None:
+ self.map.RaiseLayer(layer)
+ else:
+ assert False, "Shouldn't be allowed."
+ pass
+
+ def MoveCurrentItemDown(self):
+ layer, group = self.GetSelectedHierarchy()
+
+ if layer is not None:
+ self.map.LowerLayer(layer)
+ else:
+ assert False, "Shouldn't be allowed."
+ pass
+
+ def MoveCurrentItemBottom(self):
+ layer, group = self.GetSelectedHierarchy()
+
+ if layer is not None:
+ self.map.MoveLayerToBottom(layer)
+ else:
+ assert False, "Shouldn't be allowed."
+ pass
+
+ def OnCompareItems(self, item1, item2):
+
+ data1 = self.GetPyData(item1)
+ data2 = self.GetPyData(item2)
+
+ if isinstance(data1, BaseLayer):
+ layers = self.map.Layers()
+ return layers.index(data2) - layers.index(data1)
+ else:
+ return wx.TreeCtrl.OnCompareItems(self, item1, item2)
+
+ def DoOnShowLayer(self):
+ layer, group = self.GetSelectedHierarchy()
+ layer.SetVisible(True)
+
+ def DoOnHideLayer(self):
+ layer, group = self.GetSelectedHierarchy()
+ layer.SetVisible(False)
+
+ def ToggleVisibility(self):
+ layer, group = self.GetSelectedHierarchy()
+
+ layer.SetVisible(not layer.Visible())
+
+ def LayerProjection(self):
+ self.parent.mainWindow.LayerProjection()
+
+ def Sort(self):
+ self.SortChildren(self.GetRootItem())
+
+ def GetSelectedHierarchy(self):
+ id = self.GetSelection()
+
+ if not id.IsOk():
+ return (None, None)
+
+ layer = self.GetPyData(id)
+ group = None
+
+ if isinstance(layer, ClassGroup):
+ id = self.GetItemParent(id)
+ assert id.IsOk()
+ group = layer
+ layer = self.GetPyData(id)
+
+ return (layer, group)
+
+ def _OnMsgMapsChanged(self):
+ #print self.map is self.mainWindow.Map()
+ self.SetMap(self.mainWindow.Map())
+
+ def _OnSelChanged(self, event):
+ # If we change the selection from normalize_selection do nothing.
+ if self.changing_selection:
+ return
+
+ self.normalize_selection()
+ self.__UpdateSelection()
+
+ def normalize_selection(self):
+ """Select the layer containing currently selected item"""
+ # This is really a workaround for a bug in wx where deleting a
+ # subtree with DeleteChildren does not update the selection
+ # properly and can lead to segfaults later because the return
+ # value of GetSelection points to invalid data.
+ item = self.GetSelection()
+ while item.IsOk():
+ object = self.GetPyData(item)
+ if isinstance(object, BaseLayer):
+ break
+ item = self.GetItemParent(item)
+ else:
+ # No layer was found in the chain of parents, so there's
+ # nothing we can do.
+ return
+
+ self.changing_selection = 1
+ try:
+ self.SelectItem(item)
+ finally:
+ self.changing_selection = 0
+
+
+ def OnItemExpandCollapse(self, event):
+ if self.preventExpandCollapse:
+ event.Veto()
+ self.preventExpandCollapse = False
+
+ def _OnItemActivated(self, event):
+ # The following looks strange but is need under Windows to
+ # raise the Properties on double-click: The tree control
+ # always gets an Expanded / Collapsed event after the ItemActivated
+ # on double click, which raises the main window again. We add a second
+ # ItemActivated event to the queue, which simply raises the already
+ # displayed window.
+ if self.raiseProperties:
+ self.parent.DoOnProperties()
+ self.raiseProperties = False
+ else:
+ self.raiseProperties = True
+ self.preventExpandCollapse = True
+ self.parent.DoOnProperties()
+ self.AddPendingEvent(event)
+
+ def _OnMsgLayerChanged(self, layer):
+ assert isinstance(layer, BaseLayer)
+
+ id = self.find_layer(layer)
+ assert id is not None
+
+ self.__FillTreeLayer(id)
+ self.__UpdateSelection()
+
+ def _OnMsgMapStackingChanged(self, *args):
+ self.Sort()
+ id = self.GetSelection()
+
+ if id.IsOk():
+ self.EnsureVisible(id)
+ self.__UpdateSelection()
+
+ def _OnMsgMapLayersAdded(self, map):
+ assert map is self.map
+
+ # Build a dict with all layers known by the the tree as keys
+ layers = {}
+ root = self.GetRootItem()
+ id, cookie = self.GetFirstChild(root)
+ while id.IsOk():
+ layers[self.GetPyData(id)] = 1
+ id, cookie = self.GetNextChild(root, cookie)
+
+ # Add layers in the map but not in the dict
+ i = 0
+ for l in map.Layers():
+ if not l in layers:
+ self.__AddLayer(i, l)
+
+ self.__UpdateSelection()
+
+ def _OnMsgMapLayersRemoved(self, map):
+ assert map is self.map
+
+ layers = map.Layers()
+
+ root = self.GetRootItem()
+ id, cookie = self.GetFirstChild(root)
+ while id.IsOk():
+ if self.GetPyData(id) not in layers:
+ self.__RemoveLayer(id)
+ id, cookie = self.GetNextChild(root, cookie)
+
+
+ self.__UpdateSelection()
+
+ def _OnMsgLayerVisibilityChanged(self, layer):
+ assert isinstance(layer, BaseLayer)
+
+ self.__ShowHideLayer(layer)
+ self.__UpdateSelection()
+
+ def _OnMsgLayerTitleChanged(self, layer):
+
+ id = self.find_layer(layer)
+ if id.IsOk():
+ self.SetItemText(id, layer.Title())
+ self.__UpdateSelection()
+
+ def __UpdateSelection(self):
+ layer, group = self.GetSelectedHierarchy()
+ self.parent.DoOnSelChanged(layer, group)
+
+ def __FillTree(self, map):
+
+ self.Freeze()
+
+ self.DeleteAllItems()
+
+ if map.HasLayers():
+ root = self.GetRootItem()
+ for l in map.Layers():
+ self.__AddLayer(0, l)
+
+ self.Thaw()
+
+ def __FillTreeLayer(self, pid):
+
+ layer = self.GetPyData(pid)
+
+ self.Freeze()
+
+ self.DeleteChildren(pid)
+
+ if layer.HasClassification():
+
+ clazz = layer.GetClassification()
+
+ shapeType = layer.ShapeType()
+
+ show = layer.Visible()
+ for g in clazz:
+ if g.IsVisible():
+ id = self.AppendItem(pid, g.GetDisplayText())
+ self.SetPyData(id, g)
+ self.__SetVisibilityStyle(show, id)
+
+ bmp = self.__BuildGroupImage(g, shapeType)
+
+ if bmp is None:
+ self.SetItemImage(id, -1, wx.TreeItemIcon_Normal)
+ self.SetItemImage(id, -1, wx.TreeItemIcon_Selected)
+ #self.SetItemSelectedImage(id, -1)
+ else:
+ if self.availImgListIndices:
+ i = self.availImgListIndices.pop(0)
+ self.image_list.Replace(i, bmp)
+ else:
+ i = self.image_list.Add(bmp)
+
+ self.SetItemImage(id, i, wx.TreeItemIcon_Normal)
+ self.SetItemImage(id, i, wx.TreeItemIcon_Selected)
+ #self.SetItemlectedImage(id, i)
+
+ self.Thaw()
+
+ def __BuildGroupImage(self, group, shapeType):
+
+ bmp = wx.EmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
+ #brush = wxBrush(Color2wxColour(item[1]), wxSOLID)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.Clear()
+
+ self.previewer.Draw(dc, None, group.GetProperties(), shapeType)
+
+ return bmp
+
+ def DeleteAllItems(self):
+
+ pid = self.GetRootItem()
+
+ id, cookie = self.GetFirstChild(pid)
+ while id.IsOk():
+ self.__RemoveLayer(id)
+ id, cookie = self.GetNextChild(pid, cookie)
+
+ wx.TreeCtrl.DeleteAllItems(self)
+
+ def __AddLayer(self, before, l):
+ root = self.GetRootItem()
+ id = self.InsertItemBefore(root, before,
+ l.Title(),
+ self.mapImageIndex,
+ self.mapImageIndex)
+
+ self.SetPyData(id, l)
+ self.__SetVisibilityStyle(l.Visible(), id)
+
+ self.__FillTreeLayer(id)
+ self.Expand(id)
+
+ l.Subscribe(LAYER_CHANGED, self._OnMsgLayerChanged)
+ l.Subscribe(LAYER_VISIBILITY_CHANGED,
+ self._OnMsgLayerVisibilityChanged)
+ l.Subscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
+
+ def __RemoveLayer(self, id):
+ self.DeleteChildren(id)
+
+ layer = self.GetPyData(id)
+ layer.Unsubscribe(LAYER_CHANGED,
+ self._OnMsgLayerChanged)
+ layer.Unsubscribe(LAYER_VISIBILITY_CHANGED,
+ self._OnMsgLayerVisibilityChanged)
+ layer.Unsubscribe(TITLE_CHANGED, self._OnMsgLayerTitleChanged)
+
+ self.Delete(id)
+
+ def DeleteChildren(self, pid):
+ id, cookie = self.GetFirstChild(pid)
+ while id.IsOk():
+ self.availImgListIndices.append(self.GetItemImage(id))
+ id, cookie = self.GetNextChild(pid, cookie)
+ wx.TreeCtrl.DeleteChildren(self, pid)
+
+ def GetRootItem(self):
+ root = wx.TreeCtrl.GetRootItem(self)
+
+ if not root.IsOk():
+ self.image_list = wx.ImageList(BMP_SIZE_W, BMP_SIZE_H, False, 0)
+
+ bmp = wx.EmptyBitmap(BMP_SIZE_W, BMP_SIZE_H)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.SetBrush(wx.BLACK_BRUSH)
+ dc.Clear()
+ dc.SelectObject(wx.NullBitmap)
+
+ self.emptyImageIndex = \
+ self.image_list.AddWithColourMask(bmp, wx.Colour(0, 0, 0))
+
+ bmp = resource.GetBitmapResource("legend_icon_layer",
+ wx.BITMAP_TYPE_XPM)
+ self.mapImageIndex = \
+ self.image_list.Add(bmp)
+
+ self.AssignImageList(self.image_list)
+ self.availImgListIndices = []
+
+ root = self.AddRoot("")
+
+ return root
+
+ def __SetVisibilityStyle(self, visible, id):
+ font = self.GetItemFont(id)
+
+ if visible:
+ font.SetStyle(wx.NORMAL)
+ color = wx.BLACK
+ else:
+ #font.SetStyle(wxITALIC)
+ font.SetStyle(wx.NORMAL)
+ color = wx.LIGHT_GREY
+
+ self.SetItemTextColour(id, color)
+ self.SetItemFont(id, font)
+
+ def __ShowHideLayer(self, layer):
+ parent = self.find_layer(layer)
+ assert parent.IsOk()
+
+ visible = layer.Visible()
+
+ self.__SetVisibilityStyle(visible, parent)
+
+ id, cookie = self.GetFirstChild(parent)
+
+ while id.IsOk():
+ self.__SetVisibilityStyle(visible, id)
+ id, cookie = self.GetNextChild(parent, cookie)
+
+ # In wxPython 2.4 the GetFirstChild method has to be called with a
+ # second argument and in 2.5 it must not. Reading the code of
+ # wxPython 2.4 it seems that the second parameter was intended to be
+ # optional there but due to a bug in the C++ code it doesn't work
+ # and omitting the second argument leads to a segfault. To cope
+ # with this and to make the code usable with both 2.5 and 2.4 we
+ # overwrite the inherited method when running with 2.4 to provide a
+ # default value for the second argument.
+ if map(int, wx.__version__.split(".")[:2]) < [2, 5]:
+ def GetFirstChild(self, item):
+ return wx.TreeCtrl.GetFirstChild(self, item, 0)
+
+
+class ScaleBarBitmap(wx.BoxSizer):
+
+ def __init__(self, parent, map, mainWindow):
+ # While the width is fixed, get the height _now_.
+ dc = wx.MemoryDC()
+ textwidth, textheight = dc.GetTextExtent("%d"%0)
+ self.width = 210
+ self.height = textheight + 3*2 + 8
+
+ wx.BoxSizer.__init__(self, wx.VERTICAL)
+ bmp=wx.EmptyBitmap(self.width, self.height)
+ self.scalebarBitmap = wx.StaticBitmap(parent, -1, bmp)
+ self.Add(self.scalebarBitmap, 0, wx.ALIGN_CENTER|wx.LEFT|wx.TOP|wx.RIGHT, 1)
+
+ self.mainWindow = mainWindow
+ self.parent = parent
+ self.canvas = None
+ self.SetCanvas(self.mainWindow.canvas)
+
+ def SetCanvas(self, canvas):
+ sub_list = [(SCALE_CHANGED, self._OnMsgScaleChanged)]
+
+ if self.canvas is not None:
+ for msg, func in sub_list: self.canvas.Unsubscribe(msg, func)
+
+ self.canvas = canvas
+ self.scalebar = ScaleBar(canvas.map)
+
+ if self.canvas is not None:
+ for msg, func in sub_list: self.canvas.Subscribe(msg, func)
+ self.__SetScale(self.canvas.scale)
+
+ def _OnMsgScaleChanged(self, scale):
+ self.__SetScale(scale)
+
+ def __SetScale(self, scale):
+ bmp = wx.EmptyBitmap(self.width, self.height)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.Clear()
+
+ if self.canvas.map is not None \
+ and self.canvas.map.projection is not None:
+
+ # if we are using a projection with geographics coordinates
+ # we need to change the scale value based on where we are
+ # on the globe.
+ if self.canvas.map.projection.GetProjectedUnits() \
+ == PROJ_UNITS_DEGREES:
+
+ width, height = self.canvas.GetSizeTuple()
+ long, lat = self.canvas.win_to_proj(width/2, height/2)
+
+ # slightly inaccurate, but if we are looking at
+ # the north/south pole we could end up dividing by zero
+ #
+ # it shouldn't matter for our purposes that we ignore
+ # the original sign of lat.
+ if fabs(lat) > 89.9: lat = 89.9
+
+ #
+ # one degree is about 111,133m at the equator
+ # we need to adjust that for latitude as
+ # we move north/south. use the center of the map
+ # as the point to scale the length to.
+ #
+ scale = scale / (111133.0 * fabs(cos(lat * pi/180)))
+
+ self.scalebar.DrawScaleBar(scale, dc, (0,0), dc.GetSizeTuple())
+
+ self.scalebarBitmap.SetBitmap(bmp)
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/main.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/main.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/main.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,75 @@
+# Copyright (C) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+The main entry point for the Thuban GUI.
+"""
+
+__version__ = "$Revision: 2700 $"
+
+import sys
+import getopt
+
+import application
+import Thuban.version
+
+
+class options:
+
+ attribute_editing_enabled = False
+
+
+def main():
+ """Instantiate the application object and run the application"""
+
+ if verify_versions():
+ app = application.ThubanApplication(0)
+ opts, args = getopt.getopt(sys.argv[1:], '',
+ ['enable-attribute-editing'])
+ for optchar, value in opts:
+ if optchar == '--enable-attribute-editing':
+ options.attribute_editing_enabled = True
+ else:
+ print >>sys.stderr, "Unknown option", optchar
+
+ # If there was a non-flag argument it's the name of a thuban
+ # file.
+ if args:
+ app.OpenSession(args[0])
+
+ app.MainLoop()
+ # sys.excepthook is set in ThubanApplication.OnInit()
+ sys.excepthook = sys.__excepthook__
+
+
+def verify_versions():
+ """Check some library versions.
+
+ Print a message containing any libraries which are wrong.
+ Return True if everything is OK, otherwise False.
+ """
+
+ errors = Thuban.version.verify_versions()
+
+ if len(errors) > 0:
+ msg = " The following version errors were detected:"
+
+ for e in errors:
+ msg += "\n " + e
+
+# if use_msg_box:
+# # XXX: use a message box to display the errors
+# pass
+
+ print "\n*******************************************************"
+ print msg
+ print "*******************************************************\n"
+
+ return False
+
+ return True
Added: packages/thuban/branches/upstream/current/Thuban/UI/mainwindow.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/mainwindow.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/mainwindow.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1370 @@
+# Copyright (C) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+The main window
+"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: mainwindow.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import os
+import copy
+
+import wx
+
+import Thuban
+
+from Thuban import _
+from Thuban.Model.messages import TITLE_CHANGED, LAYER_PROJECTION_CHANGED, \
+ MAP_PROJECTION_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED
+
+from Thuban.Model.session import create_empty_session
+from Thuban.Model.layer import Layer, RasterLayer
+from Thuban.Model.postgisdb import PostGISShapeStore, has_postgis_support
+from wx.lib.dialogs import MultipleChoiceDialog
+
+import view
+import tree
+import tableview, identifyview
+import legend
+from menu import Menu
+
+from context import Context
+from command import registry, Command, ToolCommand
+from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \
+ MAP_REPLACED
+from about import About
+
+from Thuban.UI.dock import DockFrame
+from Thuban.UI.join import JoinDialog
+from Thuban.UI.dbdialog import DBFrame, DBDialog, ChooseDBTableDialog
+import resource
+import Thuban.Model.resource
+
+import projdialog
+
+from Thuban.UI.classifier import Classifier
+from Thuban.UI.rasterlayerproperties import RasterLayerProperties
+from Thuban.Model.layer import RasterLayer
+
+from Thuban.Lib.classmapper import ClassMapper
+
+layer_properties_dialogs = ClassMapper()
+layer_properties_dialogs.add(RasterLayer, RasterLayerProperties)
+layer_properties_dialogs.add(Layer, Classifier)
+
+class MainWindow(DockFrame):
+
+ # Some messages that can be subscribed/unsubscribed directly through
+ # the MapCanvas come in fact from other objects. This is a map to
+ # map those messages to the names of the instance variables they
+ # actually come from. This delegation is implemented in the
+ # Subscribe and unsubscribed methods
+ delegated_messages = {LAYER_SELECTED: "canvas",
+ SHAPES_SELECTED: "canvas",
+ MAP_REPLACED: "canvas"}
+
+ # Methods delegated to some instance variables. The delegation is
+ # implemented in the __getattr__ method.
+ delegated_methods = {"SelectLayer": "canvas",
+ "SelectShapes": "canvas",
+ "SelectedLayer": "canvas",
+ "SelectedShapes": "canvas",
+ }
+
+ # Messages from the canvas that may require a status bar update.
+ # The update_status_bar method will be subscribed to these messages.
+ update_status_bar_messages = (VIEW_POSITION, LAYER_PROJECTION_CHANGED,
+ MAP_PROJECTION_CHANGED, MAP_LAYERS_ADDED,
+ MAP_LAYERS_REMOVED)
+
+ def __init__(self, parent, ID, title, application, interactor,
+ initial_message = None, size = wx.Size(-1, -1)):
+ DockFrame.__init__(self, parent, ID, title, wx.DefaultPosition, size)
+ #wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, size)
+
+ self.application = application
+
+ self.CreateStatusBar()
+ if initial_message:
+ self.SetStatusText(initial_message)
+
+ self.identify_view = None
+
+ self.init_ids()
+
+ # creat the menubar from the main_menu description
+ self.SetMenuBar(self.build_menu_bar(main_menu))
+
+ # Similarly, create the toolbar from main_toolbar
+ toolbar = self.build_toolbar(main_toolbar)
+ # call Realize to make sure that the tools appear.
+ toolbar.Realize()
+
+
+ # Create the map canvas
+ canvas = view.MapCanvas(self, -1)
+ canvas.Subscribe(SHAPES_SELECTED, self.identify_view_on_demand)
+ self.canvas = canvas
+ self.canvas.Subscribe(TITLE_CHANGED, self.title_changed)
+
+ for channel in self.update_status_bar_messages:
+ self.canvas.Subscribe(channel, self.update_status_bar)
+
+ self.SetMainWindow(self.canvas)
+
+ self.SetAutoLayout(True)
+
+ self.init_dialogs()
+
+ self.ShowLegend()
+
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+ def Subscribe(self, channel, *args):
+ """Subscribe a function to a message channel.
+
+ If channel is one of the delegated messages call the appropriate
+ object's Subscribe method. Otherwise do nothing.
+ """
+ if channel in self.delegated_messages:
+ object = getattr(self, self.delegated_messages[channel])
+ object.Subscribe(channel, *args)
+ else:
+ print "Trying to subscribe to unsupported channel %s" % channel
+
+ def Unsubscribe(self, channel, *args):
+ """Unsubscribe a function from a message channel.
+
+ If channel is one of the delegated messages call the appropriate
+ object's Unsubscribe method. Otherwise do nothing.
+ """
+ if channel in self.delegated_messages:
+ object = getattr(self, self.delegated_messages[channel])
+ try:
+ object.Unsubscribe(channel, *args)
+ except wx.PyDeadObjectError:
+ # The object was a wxObject and has already been
+ # destroyed. Hopefully it has unsubscribed all its
+ # subscribers already so that it's OK if we do nothing
+ # here
+ pass
+
+ def __getattr__(self, attr):
+ """If attr is one of the delegated methods return that method
+
+ Otherwise raise AttributeError.
+ """
+ if attr in self.delegated_methods:
+ return getattr(getattr(self, self.delegated_methods[attr]), attr)
+ raise AttributeError(attr)
+
+ def init_ids(self):
+ """Initialize the ids"""
+ self.current_id = 6000
+ self.id_to_name = {}
+ self.name_to_id = {}
+ self.events_bound = {}
+
+ def get_id(self, name):
+ """Return the wxWindows id for the command named name.
+
+ Create a new one if there isn't one yet"""
+ ID = self.name_to_id.get(name)
+ if ID is None:
+ ID = self.current_id
+ self.current_id = self.current_id + 1
+ self.name_to_id[name] = ID
+ self.id_to_name[ID] = name
+ return ID
+
+ def bind_command_events(self, command, ID):
+ """Bind the necessary events for the given command and ID"""
+ if not self.events_bound.has_key(ID):
+ # the events haven't been bound yet
+ self.Bind(wx.EVT_MENU, self.invoke_command, id=ID)
+ if command.IsDynamic():
+ self.Bind(wx.EVT_UPDATE_UI, self.update_command_ui, id=ID)
+
+ def build_menu_bar(self, menudesc):
+ """Build and return the menu bar from the menu description"""
+ menu_bar = wx.MenuBar()
+
+ for item in menudesc.items:
+ # here the items must all be Menu instances themselves
+ menu_bar.Append(self.build_menu(item), item.title)
+
+ return menu_bar
+
+ def build_menu(self, menudesc):
+ """Return a wxMenu built from the menu description menudesc"""
+ wxmenu = wx.Menu()
+ last = None
+ for item in menudesc.items:
+ if item is None:
+ # a separator. Only add one if the last item was not a
+ # separator
+ if last is not None:
+ wxmenu.AppendSeparator()
+ elif isinstance(item, Menu):
+ # a submenu
+ wxmenu.AppendMenu(wx.NewId(), item.title, self.build_menu(item))
+ else:
+ # must the name the name of a command
+ self.add_menu_command(wxmenu, item)
+ last = item
+ return wxmenu
+
+ def build_toolbar(self, toolbardesc):
+ """Build and return the main toolbar window from a toolbar description
+
+ The parameter should be an instance of the Menu class but it
+ should not contain submenus.
+ """
+ toolbar = self.CreateToolBar(wx.TB_3DBUTTONS)
+
+ # set the size of the tools' bitmaps. Not needed on wxGTK, but
+ # on Windows, although it doesn't work very well there. It seems
+ # that only 16x16 icons are really supported on windows.
+ # We probably shouldn't hardwire the bitmap size here.
+ toolbar.SetToolBitmapSize(wx.Size(24, 24))
+
+ for item in toolbardesc.items:
+ if item is None:
+ toolbar.AddSeparator()
+ else:
+ # assume it's a string.
+ self.add_toolbar_command(toolbar, item)
+
+ return toolbar
+
+ def add_menu_command(self, menu, name):
+ """Add the command with name name to the menu menu.
+
+ If name is None, add a separator.
+ """
+ if name is None:
+ menu.AppendSeparator()
+ else:
+ command = registry.Command(name)
+ if command is not None:
+ ID = self.get_id(name)
+ menu.Append(ID, command.Title(), command.HelpText(),
+ command.IsCheckCommand())
+ self.bind_command_events(command, ID)
+ else:
+ print _("Unknown command %s") % name
+
+ def add_toolbar_command(self, toolbar, name):
+ """Add the command with name name to the toolbar toolbar.
+
+ If name is None, add a separator.
+ """
+ # Assume that all toolbar commands are also menu commmands so
+ # that we don't have to add the event handlers here
+ if name is None:
+ toolbar.AddSeparator()
+ else:
+ command = registry.Command(name)
+ if command is not None:
+ ID = self.get_id(name)
+ bitmap = resource.GetBitmapResource(command.Icon(),
+ wx.BITMAP_TYPE_XPM)
+ toolbar.AddTool(ID, bitmap,
+ shortHelpString = command.HelpText(),
+ isToggle = command.IsCheckCommand())
+ self.bind_command_events(command, ID)
+ else:
+ print _("Unknown command %s") % name
+
+ def Context(self):
+ """Return the context object for a command invoked from this window
+ """
+ return Context(self.application, self.application.Session(), self)
+
+ def invoke_command(self, event):
+ name = self.id_to_name.get(event.GetId())
+ if name is not None:
+ command = registry.Command(name)
+ command.Execute(self.Context())
+ else:
+ print _("Unknown command ID %d") % event.GetId()
+
+ def update_command_ui(self, event):
+ #print "update_command_ui", self.id_to_name[event.GetId()]
+ context = self.Context()
+ command = registry.Command(self.id_to_name[event.GetId()])
+ if command is not None:
+ sensitive = command.Sensitive(context)
+ event.Enable(sensitive)
+ if command.IsTool() and not sensitive and command.Checked(context):
+ # When a checked tool command is disabled deselect all
+ # tools. Otherwise the tool would remain active but it
+ # might lead to errors if the tools stays active. This
+ # problem occurred in GREAT-ER and this fixes it, but
+ # it's not clear to me whether this is really the best
+ # way to do it (BH, 20021206).
+ self.canvas.SelectTool(None)
+ event.SetText(command.DynText(context))
+ if command.IsCheckCommand():
+ event.Check(command.Checked(context))
+
+ def RunMessageBox(self, title, text, flags = wx.OK | wx.ICON_INFORMATION):
+ """Run a modal message box with the given text, title and flags
+ and return the result"""
+ dlg = wx.MessageDialog(self, text, title, flags)
+ dlg.CenterOnParent()
+ result = dlg.ShowModal()
+ dlg.Destroy()
+ return result
+
+ def init_dialogs(self):
+ """Initialize the dialog handling"""
+ # The mainwindow maintains a dict mapping names to open
+ # non-modal dialogs. The dialogs are put into this dict when
+ # they're created and removed when they're closed
+ self.dialogs = {}
+
+ def add_dialog(self, name, dialog):
+ if self.dialogs.has_key(name):
+ raise RuntimeError(_("The Dialog named %s is already open") % name)
+ self.dialogs[name] = dialog
+
+ def dialog_open(self, name):
+ return self.dialogs.has_key(name)
+
+ def remove_dialog(self, name):
+ del self.dialogs[name]
+
+ def get_open_dialog(self, name):
+ return self.dialogs.get(name)
+
+ def update_status_bar(self, *args):
+ """Handler for a bunch of messages that may require a status bar update
+
+ Currently this handles the canvas' VIEW_POSITION_CHANGED
+ messages as well as several messages about changes in the map
+ which may affect whether and how projections are used.
+
+ These messages affect the text in the status bar in the following way:
+
+ When VIEW_POSITION_CHANGED messages are sent and the mouse is
+ actually in the canvas window, display the current mouse
+ coordinates as defined by the canvas' CurrentPosition method.
+
+ If there is no current position to show, check whether there is
+ a potential problem with the map and layer projections and
+ display a message about it. Otherwise the status bar will
+ become empty.
+
+ The text is displayed in the status bar using the
+ set_position_text method.
+ """
+ # Implementation note: We do not really have to know which
+ # message was sent. We can simply call the canvas'
+ # CurrentPosition method and if that returns a tuple, it was a
+ # VIEW_POSITION_CHANGED message and we have to display it.
+ # Otherwise it was a VIEW_POSITION_CHANGED message where the
+ # mouse has left the canvas or it was a message about a change
+ # to the map, in which case we check the projections.
+ #
+ # When changing this method, keep in mind that the
+ # VIEW_POSITION_CHANGED message are sent for every mouse move in
+ # the canvas window, that is they happen very often, so the path
+ # taken in that case has to be fast.
+ text = ""
+ pos = self.canvas.CurrentPosition()
+ if pos is not None:
+ text = "(%10.10g, %10.10g)" % pos
+ else:
+ for layer in self.canvas.Map().Layers():
+ bbox = layer.LatLongBoundingBox()
+ if bbox:
+ left, bottom, right, top = bbox
+ if not (-180 <= left <= 180 and
+ -180 <= right <= 180 and
+ -90 <= top <= 90 and
+ -90 <= bottom <= 90):
+ text = _("Select layer '%s' and pick a projection "
+ "using Layer/Projection...") % layer.title
+ break
+
+ self.set_position_text(text)
+
+ def set_position_text(self, text):
+ """Set the statusbar text to that created by update_status_bar
+
+ By default the text is shown in field 0 of the status bar.
+ Override this method in derived classes to put it into a
+ different field of the statusbar.
+
+ For historical reasons this method is called set_position_text
+ because at first the text was always either the current position
+ or the empty string. Now it can contain other messages as well.
+ The method will be renamed at one point.
+ """
+ # Note: If this method is renamed we should perhaps think about
+ # some backwards compatibility measures for projects like
+ # GREAT-ER which override this method.
+ self.SetStatusText(text)
+
+ def OpenOrRaiseDialog(self, name, dialog_class, *args, **kw):
+ """
+ Open or raise a dialog.
+
+ If a dialog with the denoted name does already exist it is
+ raised. Otherwise a new dialog, an instance of dialog_class,
+ is created, inserted into the main list and displayed.
+ """
+ dialog = self.get_open_dialog(name)
+
+ if dialog is None:
+ dialog = dialog_class(self, name, *args, **kw)
+ self.add_dialog(name, dialog)
+ dialog.Show(True)
+ else:
+ dialog.Raise()
+
+ def save_modified_session(self, can_veto = 1):
+ """If the current session has been modified, ask the user
+ whether to save it and do so if requested. Return the outcome of
+ the dialog (either wxID_OK, wxID_CANCEL or wxID_NO). If the
+ dialog wasn't run return wxID_NO.
+
+ If the can_veto parameter is true (default) the dialog includes
+ a cancel button, otherwise not.
+ """
+ if self.application.session.WasModified():
+ flags = wx.YES_NO | wx.ICON_QUESTION
+ if can_veto:
+ flags = flags | wx.CANCEL
+ result = self.RunMessageBox(_("Exit"),
+ _("The session has been modified."
+ " Do you want to save it?"),
+ flags)
+ if result == wx.ID_YES:
+ self.SaveSession()
+ else:
+ result = wx.ID_NO
+ return result
+
+ def NewSession(self):
+ if self.save_modified_session() != wx.ID_CANCEL:
+ self.application.SetSession(create_empty_session())
+
+ def OpenSession(self):
+ if self.save_modified_session() != wx.ID_CANCEL:
+ dlg = wx.FileDialog(self, _("Open Session"),
+ self.application.Path("data"), "",
+ "Thuban Session File (*.thuban)|*.thuban",
+ wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.application.OpenSession(dlg.GetPath(),
+ self.run_db_param_dialog)
+ self.application.SetPath("data", dlg.GetPath())
+ dlg.Destroy()
+
+ def run_db_param_dialog(self, parameters, message):
+ dlg = DBDialog(self, _("DB Connection Parameters"), parameters,
+ message)
+ return dlg.RunDialog()
+
+ def SaveSession(self):
+ if self.application.session.filename == None:
+ self.SaveSessionAs()
+ else:
+ self.application.SaveSession()
+
+ def SaveSessionAs(self):
+ dlg = wx.FileDialog(self, _("Save Session As"),
+ self.application.Path("data"), "",
+ "Thuban Session File (*.thuban)|*.thuban",
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.application.session.SetFilename(dlg.GetPath())
+ self.application.SaveSession()
+ self.application.SetPath("data",dlg.GetPath())
+ dlg.Destroy()
+
+ def Exit(self):
+ self.Close(False)
+
+ def OnClose(self, event):
+ result = self.save_modified_session(can_veto = event.CanVeto())
+ if result == wx.ID_CANCEL:
+ event.Veto()
+ else:
+ # FIXME: it would be better to tie the unsubscription to
+ # wx's destroy event, but that isn't implemented for wxGTK
+ # yet.
+ for channel in self.update_status_bar_messages:
+ self.canvas.Unsubscribe(channel, self.update_status_bar)
+
+ DockFrame.OnClose(self, event)
+ for dlg in self.dialogs.values():
+ dlg.Destroy()
+ self.canvas.Destroy()
+ self.Destroy()
+
+ def SetMap(self, map):
+ self.canvas.SetMap(map)
+ self.update_title()
+
+ dialog = self.FindRegisteredDock("legend")
+ if dialog is not None:
+ dialog.GetPanel().SetMap(self.Map())
+
+ def Map(self):
+ """Return the map displayed by this mainwindow"""
+
+ return self.canvas.Map()
+
+ def ToggleSessionTree(self):
+ """If the session tree is shown close it otherwise create a new tree"""
+ name = "session_tree"
+ dialog = self.get_open_dialog(name)
+ if dialog is None:
+ dialog = tree.SessionTreeView(self, self.application, name)
+ self.add_dialog(name, dialog)
+ dialog.Show(True)
+ else:
+ dialog.Close()
+
+ def SessionTreeShown(self):
+ """Return true iff the session tree is currently shown"""
+ return self.get_open_dialog("session_tree") is not None
+
+ def About(self):
+ dlg = About(self)
+ dlg.ShowModal()
+ dlg.Destroy()
+
+ def DatabaseManagement(self):
+ name = "dbmanagement"
+ dialog = self.get_open_dialog(name)
+ if dialog is None:
+ map = self.canvas.Map()
+ dialog = DBFrame(self, name, self.application.Session())
+ self.add_dialog(name, dialog)
+ dialog.Show()
+ dialog.Raise()
+
+ def AddLayer(self):
+ dlg = wx.FileDialog(self, _("Select one or more data files"),
+ self.application.Path("data"), "",
+ _("Shapefiles (*.shp)") + "|*.shp;*.SHP|" +
+ _("All Files (*.*)") + "|*.*",
+ wx.OPEN | wx.MULTIPLE)
+ if dlg.ShowModal() == wx.ID_OK:
+ filenames = dlg.GetPaths()
+ for filename in filenames:
+ title = os.path.splitext(os.path.basename(filename))[0]
+ map = self.canvas.Map()
+ has_layers = map.HasLayers()
+ try:
+ store = self.application.Session().OpenShapefile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ self.RunMessageBox(_("Add Layer"),
+ _("Can't open the file '%s'.")%filename)
+ else:
+ layer = Layer(title, store)
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ self.canvas.FitMapToWindow()
+ self.application.SetPath("data",filename)
+ dlg.Destroy()
+
+ def AddRasterLayer(self):
+ dlg = wx.FileDialog(self, _("Select an image file"),
+ self.application.Path("data"), "", "*.*",
+ wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ title = os.path.splitext(os.path.basename(filename))[0]
+ map = self.canvas.Map()
+ has_layers = map.HasLayers()
+ try:
+ layer = RasterLayer(title, filename)
+ except IOError:
+ # the layer couldn't be opened
+ self.RunMessageBox(_("Add Image Layer"),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ map.AddLayer(layer)
+ if not has_layers:
+ # if we're adding a layer to an empty map, fit the
+ # new map to the window
+ self.canvas.FitMapToWindow()
+ self.application.SetPath("data", filename)
+ dlg.Destroy()
+
+ def AddDBLayer(self):
+ """Add a layer read from a database"""
+ session = self.application.Session()
+ dlg = ChooseDBTableDialog(self, self.application.Session())
+
+ if dlg.ShowModal() == wx.ID_OK:
+ dbconn, dbtable, id_column, geo_column = dlg.GetTable()
+ try:
+ title = str(dbtable)
+
+ # Chose the correct Interface for the database type
+ store = session.OpenDBShapeStore(dbconn, dbtable,
+ id_column = id_column,
+ geometry_column = geo_column)
+ layer = Layer(title, store)
+ except:
+ # Some error occured while initializing the layer
+ self.RunMessageBox(_("Add Layer from database"),
+ _("Can't open the database table '%s'")
+ % dbtable)
+ return
+
+ map = self.canvas.Map()
+
+ has_layers = map.HasLayers()
+ map.AddLayer(layer)
+ if not has_layers:
+ self.canvas.FitMapToWindow()
+
+ dlg.Destroy()
+
+ def RemoveLayer(self):
+ layer = self.current_layer()
+ if layer is not None:
+ self.canvas.Map().RemoveLayer(layer)
+
+ def CanRemoveLayer(self):
+ """Return true if the currently selected layer can be deleted.
+
+ If no layer is selected return False.
+
+ The return value of this method determines whether the remove
+ layer command is sensitive in menu.
+ """
+ layer = self.current_layer()
+ if layer is not None:
+ return self.canvas.Map().CanRemoveLayer(layer)
+ return False
+
+ def LayerToTop(self):
+ layer = self.current_layer()
+ if layer is not None:
+ self.canvas.Map().MoveLayerToTop(layer)
+
+ def RaiseLayer(self):
+ layer = self.current_layer()
+ if layer is not None:
+ self.canvas.Map().RaiseLayer(layer)
+
+ def LowerLayer(self):
+ layer = self.current_layer()
+ if layer is not None:
+ self.canvas.Map().LowerLayer(layer)
+
+ def LayerToBottom(self):
+ layer = self.current_layer()
+ if layer is not None:
+ self.canvas.Map().MoveLayerToBottom(layer)
+
+ def current_layer(self):
+ """Return the currently selected layer.
+
+ If no layer is selected, return None
+ """
+ return self.canvas.SelectedLayer()
+
+ def has_selected_layer(self):
+ """Return true if a layer is currently selected"""
+ return self.canvas.HasSelectedLayer()
+
+ def has_selected_shape_layer(self):
+ """Return true if a shape layer is currently selected"""
+ return isinstance(self.current_layer(), Layer)
+
+ def has_selected_shapes(self):
+ """Return true if a shape is currently selected"""
+ return self.canvas.HasSelectedShapes()
+
+ def HideLayer(self):
+ layer = self.current_layer()
+ if layer is not None:
+ layer.SetVisible(False)
+
+ def ShowLayer(self):
+ layer = self.current_layer()
+ if layer is not None:
+ layer.SetVisible(True)
+
+ def ToggleLayerVisibility(self):
+ layer = self.current_layer()
+ layer.SetVisible(not layer.Visible())
+
+ def DuplicateLayer(self):
+ """Ceate a new layer above the selected layer with the same shapestore
+ """
+ layer = self.current_layer()
+ if layer is not None and hasattr(layer, "ShapeStore"):
+ new_layer = Layer(_("Copy of `%s'") % layer.Title(),
+ layer.ShapeStore(),
+ projection = layer.GetProjection())
+ new_classification = copy.deepcopy(layer.GetClassification())
+ new_layer.SetClassificationColumn(
+ layer.GetClassificationColumn())
+ new_layer.SetClassification(new_classification)
+ self.Map().AddLayer(new_layer)
+
+ def CanDuplicateLayer(self):
+ """Return whether the DuplicateLayer method can create a duplicate"""
+ layer = self.current_layer()
+ return layer is not None and hasattr(layer, "ShapeStore")
+
+ def LayerShowTable(self):
+ """
+ Present a TableView Window for the current layer.
+ In case the window is already open, bring it to the front.
+ In case, there is no active layer, do nothing.
+ In case, the layer has no ShapeStore, do nothing.
+ """
+ layer = self.current_layer()
+ if layer is not None:
+ if not hasattr(layer, "ShapeStore"):
+ return
+ table = layer.ShapeStore().Table()
+ name = "table_view" + str(id(table))
+ dialog = self.get_open_dialog(name)
+ if dialog is None:
+ dialog = tableview.LayerTableFrame(self, name,
+ _("Layer Table: %s") % layer.Title(),
+ layer, table)
+ self.add_dialog(name, dialog)
+ dialog.Show(True)
+ else:
+ dialog.Raise()
+
+ def MapProjection(self):
+
+ name = "map_projection"
+ dialog = self.get_open_dialog(name)
+
+ if dialog is None:
+ map = self.canvas.Map()
+ dialog = projdialog.ProjFrame(self, name,
+ _("Map Projection: %s") % map.Title(), map)
+ self.add_dialog(name, dialog)
+ dialog.Show()
+ dialog.Raise()
+
+ def LayerProjection(self):
+
+ layer = self.current_layer()
+
+ name = "layer_projection" + str(id(layer))
+ dialog = self.get_open_dialog(name)
+
+ if dialog is None:
+ map = self.canvas.Map()
+ dialog = projdialog.ProjFrame(self, name,
+ _("Layer Projection: %s") % layer.Title(), layer)
+ self.add_dialog(name, dialog)
+ dialog.Show()
+ dialog.Raise()
+
+ def LayerEditProperties(self):
+
+ #
+ # the menu option for this should only be available if there
+ # is a current layer, so we don't need to check if the
+ # current layer is None
+ #
+
+ layer = self.current_layer()
+ self.OpenLayerProperties(layer)
+
+ def OpenLayerProperties(self, layer, group = None):
+ """
+ Open or raise the properties dialog.
+
+ This method opens or raises the properties dialog for the
+ currently selected layer if one is defined for this layer
+ type.
+ """
+ dialog_class = layer_properties_dialogs.get(layer)
+
+ if dialog_class is not None:
+ name = "layer_properties" + str(id(layer))
+ self.OpenOrRaiseDialog(name, dialog_class, layer, group = group)
+
+ def LayerJoinTable(self):
+ layer = self.canvas.SelectedLayer()
+ if layer is not None:
+ dlg = JoinDialog(self, _("Join Layer with Table"),
+ self.application.session,
+ layer = layer)
+ dlg.ShowModal()
+
+ def LayerUnjoinTable(self):
+ layer = self.canvas.SelectedLayer()
+ if layer is not None:
+ orig_store = layer.ShapeStore().OrigShapeStore()
+ if orig_store:
+ layer.SetShapeStore(orig_store)
+
+ def ShowLegend(self):
+ if not self.LegendShown():
+ self.ToggleLegend()
+
+ def ToggleLegend(self):
+ """Show the legend if it's not shown otherwise hide it again"""
+ name = "legend"
+ dialog = self.FindRegisteredDock(name)
+
+ if dialog is None:
+ dialog = self.CreateDock(name, -1, _("Legend"), wx.LAYOUT_LEFT)
+ legend.LegendPanel(dialog, None, self)
+ dialog.Dock()
+ dialog.GetPanel().SetMap(self.Map())
+ dialog.Show()
+ else:
+ dialog.Show(not dialog.IsShown())
+
+ def LegendShown(self):
+ """Return true iff the legend is currently open"""
+ dialog = self.FindRegisteredDock("legend")
+ return dialog is not None and dialog.IsShown()
+
+ def TableOpen(self):
+ dlg = wx.FileDialog(self, _("Open Table"),
+ self.application.Path("data"), "",
+ _("DBF Files (*.dbf)") + "|*.dbf|" +
+ #_("CSV Files (*.csv)") + "|*.csv|" +
+ _("All Files (*.*)") + "|*.*",
+ wx.OPEN)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ dlg.Destroy()
+ try:
+ table = self.application.session.OpenTableFile(filename)
+ except IOError:
+ # the layer couldn't be opened
+ self.RunMessageBox(_("Open Table"),
+ _("Can't open the file '%s'.") % filename)
+ else:
+ self.ShowTableView(table)
+ self.application.SetPath("data",filename)
+
+ def TableClose(self):
+ tables = self.application.session.UnreferencedTables()
+
+ lst = [(t.Title(), t) for t in tables]
+ lst.sort()
+ titles = [i[0] for i in lst]
+ dlg = MultipleChoiceDialog(self, _("Pick the tables to close:"),
+ _("Close Table"), titles,
+ size = (400, 300),
+ style = wx.DEFAULT_DIALOG_STYLE |
+ wx.RESIZE_BORDER)
+ if dlg.ShowModal() == wx.ID_OK:
+ for i in dlg.GetValue():
+ self.application.session.RemoveTable(lst[i][1])
+
+
+ def TableShow(self):
+ """Offer a multi-selection dialog for tables to be displayed
+
+ The windows for the selected tables are opened or brought to
+ the front.
+ """
+ tables = self.application.session.Tables()
+
+ lst = [(t.Title(), t) for t in tables]
+ lst.sort()
+ titles = [i[0] for i in lst]
+ dlg = MultipleChoiceDialog(self, _("Pick the table to show:"),
+ _("Show Table"), titles,
+ size = (400,300),
+ style = wx.DEFAULT_DIALOG_STYLE |
+ wx.RESIZE_BORDER)
+ if (dlg.ShowModal() == wx.ID_OK):
+ for i in dlg.GetValue():
+ # XXX: if the table belongs to a layer, open a
+ # LayerTableFrame instead of QueryTableFrame
+ self.ShowTableView(lst[i][1])
+
+ def TableJoin(self):
+ dlg = JoinDialog(self, _("Join Tables"), self.application.session)
+ dlg.ShowModal()
+
+ def ShowTableView(self, table):
+ """Open a table view for the table and optionally"""
+ name = "table_view%d" % id(table)
+ dialog = self.get_open_dialog(name)
+ if dialog is None:
+ dialog = tableview.QueryTableFrame(self, name,
+ _("Table: %s") % table.Title(),
+ table)
+ self.add_dialog(name, dialog)
+ dialog.Show(True)
+ dialog.Raise()
+
+ def TableRename(self):
+ """Let the user rename a table"""
+
+ # First, let the user select a table
+ tables = self.application.session.Tables()
+ lst = [(t.Title(), t) for t in tables]
+ lst.sort()
+ titles = [i[0] for i in lst]
+ dlg = MultipleChoiceDialog(self, _("Pick the table to rename:"),
+ _("Rename Table"), titles,
+ size = (400,300),
+ style = wx.DEFAULT_DIALOG_STYLE |
+ wx.RESIZE_BORDER)
+ if (dlg.ShowModal() == wx.ID_OK):
+ to_rename = [lst[i][1] for i in dlg.GetValue()]
+ dlg.Destroy()
+ else:
+ to_rename = []
+
+ # Second, let the user rename the layers
+ for table in to_rename:
+ dlg = wx.TextEntryDialog(self, _("Table Title:"), _("Rename Table"),
+ table.Title())
+ try:
+ if dlg.ShowModal() == wx.ID_OK:
+ title = dlg.GetValue()
+ if title != "":
+ table.SetTitle(title)
+
+ # Make sure the session is marked as modified.
+ # FIXME: This should be handled automatically,
+ # but that requires more changes to the tables
+ # than I have time for currently.
+ self.application.session.changed()
+ finally:
+ dlg.Destroy()
+
+
+ def ZoomInTool(self):
+ self.canvas.ZoomInTool()
+
+ def ZoomOutTool(self):
+ self.canvas.ZoomOutTool()
+
+ def PanTool(self):
+ self.canvas.PanTool()
+
+ def IdentifyTool(self):
+ self.canvas.IdentifyTool()
+ self.identify_view_on_demand(None, None)
+
+ def LabelTool(self):
+ self.canvas.LabelTool()
+
+ def FullExtent(self):
+ self.canvas.FitMapToWindow()
+
+ def FullLayerExtent(self):
+ self.canvas.FitLayerToWindow(self.current_layer())
+
+ def FullSelectionExtent(self):
+ self.canvas.FitSelectedToWindow()
+
+ def ExportMap(self):
+ self.canvas.Export()
+
+ def PrintMap(self):
+ self.canvas.Print()
+
+ def RenameMap(self):
+ dlg = wx.TextEntryDialog(self, _("Map Title:"), _("Rename Map"),
+ self.Map().Title())
+ if dlg.ShowModal() == wx.ID_OK:
+ title = dlg.GetValue()
+ if title != "":
+ self.Map().SetTitle(title)
+
+ dlg.Destroy()
+
+ def RenameLayer(self):
+ """Let the user rename the currently selected layer"""
+ layer = self.current_layer()
+ if layer is not None:
+ dlg = wx.TextEntryDialog(self, _("Layer Title:"), _("Rename Layer"),
+ layer.Title())
+ try:
+ if dlg.ShowModal() == wx.ID_OK:
+ title = dlg.GetValue()
+ if title != "":
+ layer.SetTitle(title)
+ finally:
+ dlg.Destroy()
+
+ def identify_view_on_demand(self, layer, shapes):
+ """Subscribed to the canvas' SHAPES_SELECTED message
+
+ If the current tool is the identify tool, at least one shape is
+ selected and the identify dialog is not shown, show the dialog.
+ """
+ # If the selection has become empty we don't need to do
+ # anything. Otherwise it could happen that the dialog was popped
+ # up when the selection became empty, e.g. when a new selection
+ # is opened while the identify tool is active and dialog had
+ # been closed
+ if not shapes:
+ return
+
+ name = "identify_view"
+ if self.canvas.CurrentTool() == "IdentifyTool":
+ if not self.dialog_open(name):
+ dialog = identifyview.IdentifyView(self, name)
+ self.add_dialog(name, dialog)
+ dialog.Show(True)
+ else:
+ # FIXME: bring dialog to front?
+ pass
+
+ def title_changed(self, map):
+ """Subscribed to the canvas' TITLE_CHANGED messages"""
+ self.update_title()
+
+ def update_title(self):
+ """Update the window's title according to it's current state.
+
+ In this default implementation the title is 'Thuban - ' followed
+ by the map's title or simply 'Thuban' if there is not map.
+ Derived classes should override this method to get different
+ titles.
+
+ This method is called automatically by other methods when the
+ title may have to change. For the methods implemented in this
+ class this usually only means that a different map has been set
+ or the current map's title has changed.
+ """
+ map = self.Map()
+ if map is not None:
+ title = _("Thuban - %s") % (map.Title(),)
+ else:
+ title = _("Thuban")
+ self.SetTitle(title)
+
+
+#
+# Define all the commands available in the main window
+#
+
+
+# Helper functions to define common command implementations
+def call_method(context, methodname, *args):
+ """Call the mainwindow's method methodname with args *args"""
+ apply(getattr(context.mainwindow, methodname), args)
+
+def _method_command(name, title, method, helptext = "",
+ icon = "", sensitive = None, checked = None):
+ """Add a command implemented by a method of the mainwindow object"""
+ registry.Add(Command(name, title, call_method, args=(method,),
+ helptext = helptext, icon = icon,
+ sensitive = sensitive, checked = checked))
+
+def make_check_current_tool(toolname):
+ """Return a function that tests if the currently active tool is toolname
+
+ The returned function can be called with the context and returns
+ true iff the currently active tool's name is toolname. It's directly
+ usable as the 'checked' callback of a command.
+ """
+ def check_current_tool(context, name=toolname):
+ return context.mainwindow.canvas.CurrentTool() == name
+ return check_current_tool
+
+def _tool_command(name, title, method, toolname, helptext = "",
+ icon = "", sensitive = None):
+ """Add a tool command"""
+ registry.Add(ToolCommand(name, title, call_method, args=(method,),
+ helptext = helptext, icon = icon,
+ checked = make_check_current_tool(toolname),
+ sensitive = sensitive))
+
+def _has_selected_layer(context):
+ """Return true if a layer is selected in the context"""
+ return context.mainwindow.has_selected_layer()
+
+def _has_selected_layer_visible(context):
+ """Return true if a layer is selected in the context which is
+ visible."""
+ if context.mainwindow.has_selected_layer():
+ layer = context.mainwindow.current_layer()
+ if layer.Visible(): return True
+ return False
+
+def _has_selected_shape_layer(context):
+ """Return true if a shape layer is selected in the context"""
+ return context.mainwindow.has_selected_shape_layer()
+
+def _has_selected_shapes(context):
+ """Return true if a layer is selected in the context"""
+ return context.mainwindow.has_selected_shapes()
+
+def _can_remove_layer(context):
+ return context.mainwindow.CanRemoveLayer()
+
+def _has_tree_window_shown(context):
+ """Return true if the tree window is shown"""
+ return context.mainwindow.SessionTreeShown()
+
+def _has_visible_map(context):
+ """Return true iff theres a visible map in the mainwindow.
+
+ A visible map is a map with at least one visible layer."""
+ map = context.mainwindow.Map()
+ if map is not None:
+ for layer in map.Layers():
+ if layer.Visible():
+ return True
+ return False
+
+def _has_legend_shown(context):
+ """Return true if the legend window is shown"""
+ return context.mainwindow.LegendShown()
+
+def _has_gdal_support(context):
+ """Return True if the GDAL is available"""
+ return Thuban.Model.resource.has_gdal_support()
+
+def _has_dbconnections(context):
+ """Return whether the the session has database connections"""
+ return context.session.HasDBConnections()
+
+def _has_postgis_support(context):
+ return has_postgis_support()
+
+
+# File menu
+_method_command("new_session", _("&New Session"), "NewSession",
+ helptext = _("Start a new session"))
+_method_command("open_session", _("&Open Session..."), "OpenSession",
+ helptext = _("Open a session file"))
+_method_command("save_session", _("&Save Session"), "SaveSession",
+ helptext =_("Save this session to the file it was opened from"))
+_method_command("save_session_as", _("Save Session &As..."), "SaveSessionAs",
+ helptext = _("Save this session to a new file"))
+_method_command("toggle_session_tree", _("Session &Tree"), "ToggleSessionTree",
+ checked = _has_tree_window_shown,
+ helptext = _("Toggle on/off the session tree analysis window"))
+_method_command("toggle_legend", _("Legend"), "ToggleLegend",
+ checked = _has_legend_shown,
+ helptext = _("Toggle Legend on/off"))
+_method_command("database_management", _("&Database Connections..."),
+ "DatabaseManagement",
+ sensitive = _has_postgis_support)
+_method_command("exit", _("E&xit"), "Exit",
+ helptext = _("Finish working with Thuban"))
+
+# Help menu
+_method_command("help_about", _("&About..."), "About",
+ helptext = _("Info about Thuban authors, version and modules"))
+
+
+# Map menu
+_method_command("map_projection", _("Pro&jection..."), "MapProjection",
+ helptext = _("Set or change the map projection"))
+
+_tool_command("map_zoom_in_tool", _("&Zoom in"), "ZoomInTool", "ZoomInTool",
+ helptext = _("Switch to map-mode 'zoom-in'"), icon = "zoom_in",
+ sensitive = _has_visible_map)
+_tool_command("map_zoom_out_tool", _("Zoom &out"), "ZoomOutTool", "ZoomOutTool",
+ helptext = _("Switch to map-mode 'zoom-out'"), icon = "zoom_out",
+ sensitive = _has_visible_map)
+_tool_command("map_pan_tool", _("&Pan"), "PanTool", "PanTool",
+ helptext = _("Switch to map-mode 'pan'"), icon = "pan",
+ sensitive = _has_visible_map)
+_tool_command("map_identify_tool", _("&Identify"), "IdentifyTool",
+ "IdentifyTool",
+ helptext = _("Switch to map-mode 'identify'"), icon = "identify",
+ sensitive = _has_visible_map)
+_tool_command("map_label_tool", _("&Label"), "LabelTool", "LabelTool",
+ helptext = _("Add/Remove labels"), icon = "label",
+ sensitive = _has_visible_map)
+_method_command("map_full_extent", _("&Full extent"), "FullExtent",
+ helptext = _("Zoom to the full map extent"), icon = "fullextent",
+ sensitive = _has_visible_map)
+_method_command("layer_full_extent", _("&Full layer extent"), "FullLayerExtent",
+ helptext = _("Zoom to the full layer extent"),
+ icon = "fulllayerextent", sensitive = _has_selected_layer)
+_method_command("selected_full_extent", _("&Full selection extent"),
+ "FullSelectionExtent",
+ helptext = _("Zoom to the full selection extent"),
+ icon = "fullselextent", sensitive = _has_selected_shapes)
+_method_command("map_export", _("E&xport"), "ExportMap",
+ helptext = _("Export the map to file"))
+_method_command("map_print", _("Prin&t"), "PrintMap",
+ helptext = _("Print the map"))
+_method_command("map_rename", _("&Rename..."), "RenameMap",
+ helptext = _("Rename the map"))
+_method_command("layer_add", _("&Add Layer..."), "AddLayer",
+ helptext = _("Add a new layer to the map"))
+_method_command("rasterlayer_add", _("&Add Image Layer..."), "AddRasterLayer",
+ helptext = _("Add a new image layer to the map"),
+ sensitive = _has_gdal_support)
+_method_command("layer_add_db", _("Add &Database Layer..."), "AddDBLayer",
+ helptext = _("Add a new database layer to active map"),
+ sensitive = _has_dbconnections)
+_method_command("layer_remove", _("&Remove Layer"), "RemoveLayer",
+ helptext = _("Remove selected layer"),
+ sensitive = _can_remove_layer)
+
+# Layer menu
+_method_command("layer_projection", _("Pro&jection..."), "LayerProjection",
+ sensitive = _has_selected_layer,
+ helptext = _("Specify projection for selected layer"))
+_method_command("layer_duplicate", _("&Duplicate"), "DuplicateLayer",
+ helptext = _("Duplicate selected layer"),
+ sensitive = lambda context: context.mainwindow.CanDuplicateLayer())
+_method_command("layer_rename", _("Re&name ..."), "RenameLayer",
+ helptext = _("Rename selected layer"),
+ sensitive = _has_selected_layer)
+_method_command("layer_raise", _("&Raise"), "RaiseLayer",
+ helptext = _("Raise selected layer"),
+ sensitive = _has_selected_layer)
+_method_command("layer_lower", _("&Lower"), "LowerLayer",
+ helptext = _("Lower selected layer"),
+ sensitive = _has_selected_layer)
+_method_command("layer_show", _("&Show"), "ShowLayer",
+ helptext = _("Make selected layer visible"),
+ sensitive = _has_selected_layer)
+_method_command("layer_hide", _("&Hide"), "HideLayer",
+ helptext = _("Make selected layer unvisible"),
+ sensitive = _has_selected_layer)
+_method_command("layer_show_table", _("Show Ta&ble"), "LayerShowTable",
+ helptext = _("Show the selected layer's table"),
+ sensitive = _has_selected_shape_layer)
+_method_command("layer_properties", _("&Properties..."), "LayerEditProperties",
+ sensitive = _has_selected_layer,
+ helptext = _("Edit the properties of the selected layer"))
+_method_command("layer_jointable", _("&Join Table..."), "LayerJoinTable",
+ sensitive = _has_selected_shape_layer,
+ helptext = _("Join and attach a table to the selected layer"))
+
+# further layer methods:
+_method_command("layer_to_top", _("&Top"), "LayerToTop",
+ helptext = _("Put selected layer to the top"),
+ sensitive = _has_selected_layer)
+_method_command("layer_to_bottom", _("&Bottom"), "LayerToBottom",
+ helptext = _("Put selected layer to the bottom"),
+ sensitive = _has_selected_layer)
+_method_command("layer_visibility", _("&Visible"), "ToggleLayerVisibility",
+ checked = _has_selected_layer_visible,
+ helptext = _("Toggle visibility of selected layer"),
+ sensitive = _has_selected_layer)
+
+def _can_unjoin(context):
+ """Return whether the Layer/Unjoin command can be executed.
+
+ This is the case if a layer is selected and that layer has a
+ shapestore that has an original shapestore.
+ """
+ layer = context.mainwindow.SelectedLayer()
+ if layer is None:
+ return 0
+ getstore = getattr(layer, "ShapeStore", None)
+ if getstore is not None:
+ return getstore().OrigShapeStore() is not None
+ else:
+ return 0
+_method_command("layer_unjointable", _("&Unjoin Table..."), "LayerUnjoinTable",
+ sensitive = _can_unjoin,
+ helptext = _("Undo the last join operation"))
+
+
+def _has_tables(context):
+ return bool(context.session.Tables())
+
+# Table menu
+_method_command("table_open", _("&Open..."), "TableOpen",
+ helptext = _("Open a DBF-table from a file"))
+_method_command("table_close", _("&Close..."), "TableClose",
+ sensitive = lambda context: bool(context.session.UnreferencedTables()),
+ helptext = _("Close one or more tables from a list"))
+_method_command("table_rename", _("&Rename..."), "TableRename",
+ sensitive = _has_tables,
+ helptext = _("Rename one or more tables"))
+_method_command("table_show", _("&Show..."), "TableShow",
+ sensitive = _has_tables,
+ helptext = _("Show one or more tables in a dialog"))
+_method_command("table_join", _("&Join..."), "TableJoin",
+ sensitive = _has_tables,
+ helptext = _("Join two tables creating a new one"))
+
+# Export only under Windows ...
+map_menu = ["layer_add", "layer_add_db", "rasterlayer_add", "layer_remove",
+ None,
+ "map_rename",
+ "map_projection",
+ None,
+ "map_zoom_in_tool", "map_zoom_out_tool",
+ "map_pan_tool",
+ "map_full_extent",
+ "layer_full_extent",
+ "selected_full_extent",
+ None,
+ "map_identify_tool", "map_label_tool",
+ None,
+ "toggle_legend",
+ None]
+if wx.Platform == '__WXMSW__':
+ map_menu.append("map_export")
+map_menu.append("map_print")
+
+# the menu structure
+main_menu = Menu("<main>", "<main>",
+ [Menu("file", _("&File"),
+ ["new_session", "open_session", None,
+ "save_session", "save_session_as", None,
+ "database_management", None,
+ "toggle_session_tree", None,
+ "exit"]),
+ Menu("map", _("&Map"), map_menu),
+ Menu("layer", _("&Layer"),
+ ["layer_rename", "layer_duplicate",
+ None,
+ "layer_raise", "layer_lower",
+ None,
+ "layer_show", "layer_hide",
+ None,
+ "layer_projection",
+ None,
+ "layer_show_table",
+ "layer_jointable",
+ "layer_unjointable",
+ None,
+ "layer_properties"]),
+ Menu("table", _("&Table"),
+ ["table_open", "table_close", "table_rename",
+ None,
+ "table_show",
+ None,
+ "table_join"]),
+ Menu("help", _("&Help"),
+ ["help_about"])])
+
+# the main toolbar
+
+main_toolbar = Menu("<toolbar>", "<toolbar>",
+ ["map_zoom_in_tool", "map_zoom_out_tool", "map_pan_tool",
+ "map_full_extent",
+ "layer_full_extent",
+ "selected_full_extent",
+ None,
+ "map_identify_tool", "map_label_tool"])
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/menu.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/menu.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/menu.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,154 @@
+# Copyright (C) 2001, 2002 by Intevation GmbH
+# Author:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Menu management"""
+
+__version__ = "$Revision: 2202 $"
+
+from Thuban import _
+
+class Menu:
+
+ """Represent a menu or submenu.
+
+ A menu has a name and a title. The name can be used to identify
+ menus internally while the title is intended for use in the GUI.
+
+ Menu items can be added with the Insert* methods.
+ """
+
+ def __init__(self, name, title, items = None):
+ """Initialize the menu.
+
+ Parameters:
+ name -- the name of the menu
+ title -- the (possibly localized) title of the menu
+ items -- (optional) a list of menu items.
+
+ The items list may contains strings with command names, None to
+ indicate separators or Menu instances for submenus.
+ """
+ self.name = name
+ self.title = title
+ if items is None:
+ self.items = []
+ else:
+ self.items = items
+
+ def item_index(self, item):
+ """Return the index of item in the menu.
+
+ item -- may be the name of a non-menu entry or the
+ name of a menu or a menu itself.
+
+ Return None it item is not found.
+ """
+ for i in range(len(self.items)):
+ temp = self.items[i]
+ if temp == item:
+ # this case takes care of item being the name of an
+ # entry or a menu.
+ return i
+ elif isinstance(temp, Menu) and temp.name == item:
+ # item is the name of a menu
+ return i
+ # Didn't find the item so return None
+ return None
+
+ def find_menu(self, name):
+ """Return the submenu named name or None if no such item exists"""
+ for item in self.items:
+ if isinstance(item, Menu) and item.name == name:
+ return item
+ return None
+
+ def InsertItem(self, item, menu = (), after = None):
+ """Insert a menu item.
+
+ Parameters:
+
+ item -- the menu item to insert must be either a string with
+ the command's name or a Menu instance.
+
+ menu -- (optional) the submenu to insert into. It should be a
+ sequence of menu names.
+
+ after -- (optional) insert the new item after this one. after
+ should be the name of a command.
+ """
+ # if menu is given, get the first submenu
+ if menu:
+ submenu_index = self.find_menu(menu[0])
+ if submenu_index is not None:
+ submenu_index.InsertItem(item, menu = menu[1:], after = after)
+ else:
+ # the submenu doesn't exist yet. Raise an error.
+ raise KeyError(_("Submenu %s doesn't exist") % menu[0])
+ else:
+ if after is not None:
+ idx = self.item_index(after)
+ else:
+ idx = None
+
+ if idx is not None:
+ self.items.insert(idx + 1, item)
+ else:
+ self.items.append(item)
+
+ def InsertSeparator(self, after = None):
+ """Insert a separator
+
+ after -- (optional) insert the separator after this one. after
+ should be the name of a command.
+ """
+ self.InsertItem(None, after = after)
+
+ def InsertMenu(self, name, title, menu = (), after = None):
+ """Insert and return a new menu.
+
+ Parameters:
+
+ name -- the (internal) name of the menu
+
+ title -- the (possibly localized) title
+
+ menu -- (optional) the submenu to insert into. It should be a
+ sequence of menu names.
+
+ after -- (optional) insert the new item after this one. after
+ should be the name of a command.
+ """
+ newmenu = Menu(name, title)
+ self.InsertItem(newmenu, menu = menu, after = after)
+ return newmenu
+
+ def FindOrInsertMenu(self, name, title, menu = (), after = None):
+ """
+ Find the menu with the specified name. If found, return it.
+ Else insert the menu as specified and return it.
+
+ Parameters: See InsertMenu().
+ """
+
+ m = self.find_menu(name)
+ if m is None:
+ m = self.InsertMenu(name, title, menu, after)
+ return m
+
+
+ def SetItems(self, items):
+ """Replace the contents of the menu by items."""
+ self.items = items
+
+ def RemoveItem(self, item):
+ """Remove an item from the menu.
+
+ item -- the (internal) name of the item.
+ """
+ i = self.item_index(item)
+ if i is not None:
+ self.items.pop(i)
Added: packages/thuban/branches/upstream/current/Thuban/UI/messages.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/messages.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/messages.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,36 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+
+"""
+Define the message types used in Thuban's GUI. The messages types are
+simply strings. The message system itself is implemented in
+Thuban.Lib.connector.
+"""
+
+__version__ = "$Revision: 1464 $"
+
+# Application object
+SESSION_REPLACED = "SESSION_REPLACED"
+
+# events for the selection
+LAYER_SELECTED = "LAYER_SELECTED"
+SHAPES_SELECTED = "SHAPES_SELECTED"
+# obsolete selection messages.
+SELECTED_SHAPE = "SELECTED_SHAPE"
+SELECTED_LAYER = "SELECTED_LAYER"
+
+# events for the view
+VIEW_POSITION = "VIEW_POSITION"
+SCALE_CHANGED = "SCALE_CHANGED"
+MAP_REPLACED = "MAP_REPLACED"
+
+# event for a dockable window
+DOCKABLE_DOCKED = "DOCKABLE_DOCKED"
+DOCKABLE_UNDOCKED = "DOCKABLE_UNDOCKED"
+DOCKABLE_CLOSED = "DOCKABLE_CLOSED"
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/multiplechoicedialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/multiplechoicedialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/multiplechoicedialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,59 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""A dialog for entering multiple choice from a list of strings.
+
+This dialog is actually a class contained by the wxPython Library.
+However, the wxMultipleChoiceDialog did not pass the style in 2.4.0.
+
+As soon as Thuban does not support wxPython 2.4.0 any more,
+this module can be removed and the official wxMultipleChoiceDialog
+of the wxPython Library be used directly."""
+
+__version__ = "$Revision: 2700 $"
+
+import wx
+
+class wxMultipleChoiceDialog(wx.Dialog):
+ """This is a copy of the class wxPython.lib.dialogs.wxMultipleChoiceDialog
+ and fixes the bug that the style now is passed on (this is fixed
+ in version wxPython 2.4.1).
+ """
+ def __init__(self, parent, msg, title, lst, pos = wx.DefaultPosition,
+ size = (200,200), style = wx.DEFAULT_DIALOG_STYLE):
+ wx.Dialog.__init__(self, parent, -1, title, pos, size, style)
+ x, y = pos
+ if x == -1 and y == -1:
+ self.CenterOnScreen(wx.wxBOTH)
+ dc = wx.wxClientDC(self)
+ height = 0
+ for line in msg.splitlines():
+ height = height + dc.GetTextExtent(msg)[1] + 4
+ stat = wx.wxStaticText(self, -1, msg)
+ self.lbox = wx.wxListBox(self, 100, wx.wxDefaultPosition,
+ wx.wxDefaultSize, lst, wx.wxLB_MULTIPLE)
+ ok = wx.wxButton(self, wx.wxID_OK, "OK")
+ cancel = wx.wxButton(self, wx.wxID_CANCEL, "Cancel")
+ stat.SetConstraints(Layoutf('t=t10#1;l=l5#1;r=r5#1;h!%d' % (height,),
+ (self,)))
+ self.lbox.SetConstraints(Layoutf('t=b10#2;l=l5#1;r=r5#1;b=t5#3',
+ (self, stat, ok)))
+ ok.SetConstraints(Layoutf('b=b5#1;x%w25#1;w!80;h!25', (self,)))
+ cancel.SetConstraints(Layoutf('b=b5#1;x%w75#1;w!80;h!25', (self,)))
+ self.SetAutoLayout(1)
+ self.lst = lst
+ self.Layout()
+
+ def GetValue(self):
+ return self.lbox.GetSelections()
+
+ def GetValueString(self):
+ sel = self.lbox.GetSelections()
+ val = []
+ for i in sel:
+ val.append(self.lst[i])
+ return tuple(val)
Added: packages/thuban/branches/upstream/current/Thuban/UI/projdialog.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/projdialog.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/projdialog.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1050 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Projection dialog"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: projdialog.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import sys, os
+import wx
+
+from Thuban import _
+
+from Thuban.Model.proj import Projection, ProjFile
+
+from Thuban.Model.resource import get_user_proj_file, get_system_proj_file, \
+ read_proj_file, write_proj_file, \
+ DEFAULT_PROJ_FILE, EPSG_PROJ_FILE, \
+ EPSG_DEPRECATED_PROJ_FILE
+from Thuban.UI.dialogs import NonModalNonParentDialog
+
+from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+from sizers import NotebookLikeSizer
+from projlist import PROJ_SELECTION_CHANGED, ProjectionList
+from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+
+
+
+ID_PROJ_PROJCHOICE = 4002
+ID_PROJ_ADDTOLIST = 4003
+ID_PROJ_NEW = 4004
+ID_PROJ_REVERT = 4006
+ID_PROJ_AVAIL = 4009
+ID_PROJ_SAVE = 4010
+ID_PROJ_IMPORT = 4011
+ID_PROJ_EXPORT = 4012
+ID_PROJ_REMOVE = 4013
+ID_PROJ_PROJNAME = 4014
+
+CLIENT_PROJ = 0
+CLIENT_PROJFILE = 1
+
+class ProjFrame(NonModalNonParentDialog):
+
+ def __init__(self, parent, name, title, receiver):
+ """Initialize the projection dialog.
+
+ receiver -- An object that implements the following methods:
+ SetProjection(projection)
+ GetProjection()
+ """
+ NonModalNonParentDialog.__init__(self, parent, name, title)
+
+ self.projection_panel_defs = [
+ ("tmerc", _("Transverse Mercator"), TMPanel),
+ ("utm", _("Universal Transverse Mercator"), UTMPanel),
+ ("lcc", _("Lambert Conic Conformal"), LCCPanel),
+ ("latlong", _("Geographic"), GeoPanel),
+ ("longlat", _("Geographic"), GeoPanel)]#longlat is an alias of proj
+ self.receiver = receiver
+ self.haveTried = False
+ self.curProjPanel = None
+ self.__usrProjFile = None
+ self._sys_proj_files = {}
+
+ self.build_dialog()
+ self.Layout()
+
+ self.originalProjection = self.receiver.GetProjection()
+
+ self.projection_list.SelectProjection(self.originalProjection)
+ self.projection_list.SetFocus()
+
+ def build_dialog(self):
+ """Build the dialog's widgets and set the event handlers"""
+ self.topBox = top_box = wx.BoxSizer(wx.VERTICAL)
+
+ main_box = wx.BoxSizer(wx.HORIZONTAL)
+ top_box.Add(main_box, 1, wx.ALL|wx.EXPAND)
+
+ #
+ # The projection list and associated controls
+ #
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ main_box.Add(vbox, 4, wx.ALL|wx.EXPAND)
+
+ #label = wxStaticText(self, -1, _("Available Projections:"))
+ #vbox.Add(label, 0, wxLEFT|wxRIGHT|wxTOP, 4)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ vbox.Add(hbox, 1, wx.ALL|wx.EXPAND)
+ proj_files = [self.load_user_proj(),
+ self.load_system_proj(DEFAULT_PROJ_FILE)]
+ self.projection_list = ProjectionList(self, proj_files,
+ self.receiver.GetProjection())
+ hbox.Add(self.projection_list, 1, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 4)
+ self.projection_list.Subscribe(PROJ_SELECTION_CHANGED,
+ self.proj_selection_changed)
+
+ # Projection List specific actions (Import/Export/Remove)
+ buttons = wx.BoxSizer(wx.VERTICAL)
+ hbox.Add(buttons, 0, wx.ALL)
+ self.button_import = wx.Button(self, ID_PROJ_IMPORT, _("Import..."))
+ self.Bind(wx.EVT_BUTTON, self._OnImport, id=ID_PROJ_IMPORT)
+ buttons.Add(self.button_import, 1, wx.ALL|wx.EXPAND, 4)
+ self.button_export = wx.Button(self, ID_PROJ_EXPORT, _("Export..."))
+ self.Bind(wx.EVT_BUTTON, self._OnExport, id=ID_PROJ_EXPORT)
+ buttons.Add(self.button_export, 1, wx.ALL|wx.EXPAND, 4)
+ buttons.Add( (20, 20), 0, wx.EXPAND, 0)
+ self.button_remove = wx.Button(self, ID_PROJ_REMOVE, _("Remove"))
+ self.Bind(wx.EVT_BUTTON, self._OnRemove, id=ID_PROJ_REMOVE)
+ buttons.Add(self.button_remove, 1, wx.ALL|wx.EXPAND, 4)
+
+ buttons.Add( (20, 20), 0, wx.EXPAND, 0)
+ label = wx.StaticText(self, -1, _("Show EPSG:"))
+ buttons.Add(label, 0, wx.LEFT|wx.RIGHT|wx.TOP, 4)
+ self.check_epsg = wx.CheckBox(self, -1, _("Normal"))
+ self.Bind(wx.EVT_CHECKBOX, self._OnShowEPSG, id=self.check_epsg.GetId())
+ buttons.Add(self.check_epsg, 1, wx.ALL|wx.EXPAND, 4)
+ self.check_epsg_depr = wx.CheckBox(self, -1, _("Deprecated"))
+ self.Bind(wx.EVT_CHECKBOX, self._OnShowEPSG, id=self.check_epsg_depr.GetId())
+ buttons.Add(self.check_epsg_depr, 1, wx.ALL|wx.EXPAND, 4)
+
+ # The file path
+ self.projfilepath = wx.StaticText(self, -1, "")
+ vbox.Add(self.projfilepath, 0, wx.ALL|wx.EXPAND)
+
+ #
+ # The projection editor part
+ #
+ self.edit_box = wx.StaticBox(self, -1, _("Edit"))
+ sizer_edit = wx.StaticBoxSizer(self.edit_box, wx.HORIZONTAL)
+ main_box.Add(sizer_edit, 5, wx.ALL|wx.EXPAND)
+
+ # Projection Specific Entries (Name/Projection)
+ self.sizer_projctrls = wx.BoxSizer(wx.VERTICAL)
+ sizer_edit.Add(self.sizer_projctrls, 1, wx.ALL|wx.EXPAND)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer_projctrls.Add(hbox, 0, wx.ALL|wx.EXPAND)
+ label = wx.StaticText(self, -1, _("Name:"))
+ hbox.Add(label, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.projname = wx.TextCtrl(self, ID_PROJ_PROJNAME, "")
+ self.Bind(wx.EVT_TEXT, self._OnProjName, id=ID_PROJ_PROJNAME)
+ hbox.Add(self.projname, 1, wx.ALL|wx.EXPAND, 4)
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ self.sizer_projctrls.Add(hbox, 0, wx.ALL|wx.EXPAND)
+ label = wx.StaticText(self, -1, _("Projection:"))
+ hbox.Add(label, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ self.projchoice = wx.Choice(self, ID_PROJ_PROJCHOICE)
+ self.projchoice.SetSelection(0)
+ self.Bind(wx.EVT_CHOICE, self._OnProjChoice, id=ID_PROJ_PROJCHOICE)
+ hbox.Add(self.projchoice, 1, wx.ALL|wx.EXPAND, 4)
+ # Fill the projection choice list.
+ self.nbsizer = NotebookLikeSizer()
+ self.sizer_projctrls.Add(self.nbsizer, 1,
+ wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3)
+ self.projection_panels = []
+ self.projchoice.Append(_("<Unknown>"), "")
+ for proj_type, name, cls in self.projection_panel_defs:
+ self.projchoice.Append(name, proj_type)
+ panel = cls(self, self.receiver)
+ panel.Hide()
+ panel.projection_index = len(self.projection_panels)
+ panel.projection_type = proj_type
+ self.projection_panels.append(panel)
+ self.nbsizer.Add(panel)
+ self.unknown_projection_panel = UnknownProjPanel(self, self.receiver)
+ self.unknown_projection_panel.Hide()
+ self.nbsizer.Add(self.unknown_projection_panel)
+
+ # Projection Specific actions (New/Save/Add)
+ buttons = wx.BoxSizer(wx.VERTICAL)
+ sizer_edit.Add(buttons, 0, wx.ALL)
+ self.button_new = wx.Button(self, ID_PROJ_NEW, _("New"))
+ self.Bind(wx.EVT_BUTTON, self._OnNew, id=ID_PROJ_NEW)
+ buttons.Add(self.button_new, 0, wx.EXPAND|wx.ALL, 4)
+ self.button_add = wx.Button(self, ID_PROJ_ADDTOLIST, _("Add to List"))
+ self.Bind(wx.EVT_BUTTON, self._OnAddToList, id=ID_PROJ_ADDTOLIST)
+ buttons.Add(self.button_add, 0, wx.EXPAND|wx.ALL, 4)
+ buttons.Add( (20, 20), 0, wx.EXPAND, 0)
+ self.button_save = wx.Button(self, ID_PROJ_SAVE,_("Update"))
+ self.Bind(wx.EVT_BUTTON, self._OnSave, id=ID_PROJ_SAVE)
+ buttons.Add(self.button_save, 0, wx.EXPAND|wx.ALL|wx.ALIGN_BOTTOM, 4)
+
+ #
+ # Main Action buttons (Try/Revert/OK/Close)
+ #
+ buttons = wx.BoxSizer(wx.HORIZONTAL)
+ top_box.Add(buttons, 0, wx.ALL|wx.ALIGN_RIGHT, 10)
+ self.button_try = wx.Button(self, wx.ID_APPLY, _("Try"))
+ self.Bind(wx.EVT_BUTTON, self.OnApply, id=wx.ID_APPLY)
+ buttons.Add(self.button_try, 0, wx.RIGHT, 10)
+ self.button_revert = wx.Button(self, ID_PROJ_REVERT, _("Revert"))
+ self.Bind(wx.EVT_BUTTON, self._OnRevert, id=ID_PROJ_REVERT)
+ buttons.Add(self.button_revert, 0, wx.RIGHT, 10)
+ self.button_ok = wx.Button(self, wx.ID_OK, _("OK"))
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=wx.ID_OK)
+ self.button_ok.SetDefault()
+ buttons.Add(self.button_ok, 0, wx.RIGHT, 10)
+ self.button_close = wx.Button(self, wx.ID_CANCEL, _("Close"))
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=wx.ID_CANCEL)
+ buttons.Add(self.button_close, 0, wx.RIGHT, 10)
+
+
+ #
+ # Automatic Layout
+ #
+ self.SetAutoLayout(1)
+ self.SetSizer(top_box)
+ top_box.Fit(self)
+ top_box.SetSizeHints(self)
+
+ def OnClose(self, event):
+ self.projection_list.Unsubscribe(PROJ_SELECTION_CHANGED,
+ self.proj_selection_changed)
+ # Destroy the projection list explicitly so that it properly
+ # unsubscribes everything. It would be cleaner if the projection
+ # could do this by itself but wx doesn't always send destroy
+ # events for non-top-level widgets
+ self.projection_list.Destroy()
+ NonModalNonParentDialog.OnClose(self, event)
+
+ def OnApply(self, event):
+ self.__SetProjection()
+ self.haveTried = True
+
+ def OnOK(self, event):
+ self.__SetProjection()
+ self.Close()
+
+ def OnCancel(self, event):
+ """Cancel just closes the dialog, but we call it cancel so we
+ can overload the functionality of wxDialog.
+ """
+ self.Close()
+
+ def _OnRevert(self, event):
+ if self.haveTried:
+ self.receiver.SetProjection(self.originalProjection)
+ self.haveTried = False
+
+ def _OnNew(self, event):
+
+ self.projection_list.ClearSelection()
+ self.projname.Clear()
+
+ # supply a projection panel if there wasn't one
+ if self.curProjPanel is None:
+ self.projchoice.SetSelection(0)
+ self.__DoOnProjChoice()
+
+ if self.curProjPanel is not None:
+ self.curProjPanel.Clear()
+
+ def _OnSave(self, event):
+
+ sel = self.projection_list.selected_projections()
+ assert len(sel) == 1, "button shouldn't be enabled"
+
+ proj, projfile = sel[0]
+
+ assert proj is not None and projfile is not None
+
+ newproj = self.__GetProjection()
+
+ if newproj is not None:
+ # FIXME: we should only allow this for the user proj file.
+ projfile.Replace(proj, newproj)
+ self.write_proj_file(projfile)
+ self.projection_list.SelectProjection(newproj)
+
+ def _OnAddToList(self, event):
+
+ proj = self.__GetProjection()
+ if proj is not None:
+ self.__usrProjFile.Add(proj)
+ self.write_proj_file(self.__usrProjFile)
+ self.projection_list.SelectProjection(proj)
+
+ def show_warnings(self, title, filename, warnings):
+ """Show the warnings (a list of strings) in a dialog
+
+ If the list is empty no dialog will be shown.
+ """
+ if warnings:
+ text = (_('Warnings when reading "%s":\n\n%s')
+ % (filename, "\n\n".join(warnings)))
+ self.parent.RunMessageBox(title, text)
+
+ def _OnImport(self, event):
+ """Handler for the 'Import' button
+
+ Ask the user for a filename, read the projections from that file
+ add them to the user ProjFile object and write the user file
+ back to disk.
+ """
+ dlg = wx.FileDialog(self, _("Import"),
+ self.parent.application.Path("projection"), style = wx.OPEN)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ path = dlg.GetPath()
+
+ ThubanBeginBusyCursor()
+ try:
+ try:
+ projFile, warnings = read_proj_file(path)
+ except IOError, (errno, errstr):
+ self.__ShowError(dlg.GetPath(), errstr)
+ else:
+ self.show_warnings(_("Warnings"), path, warnings)
+ for proj in projFile.GetProjections():
+ self.__usrProjFile.Add(proj)
+ self.write_proj_file(self.__usrProjFile)
+ self.parent.application.SetPath("projection", path)
+ finally:
+ ThubanEndBusyCursor()
+ dlg.Destroy()
+
+ def _OnExport(self, event):
+ """Handler for the 'Export' button.
+
+ Ask the user for a filename and write the selected projections
+ to that file.
+ """
+ sel = self.projection_list.selected_projections()
+ assert len(sel) != 0, "button should be disabled"
+
+ dlg = wx.FileDialog(self, _("Export"),
+ self.parent.application.Path("projection"),
+ style=wx.SAVE|wx.OVERWRITE_PROMPT)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ proj_file = ProjFile(dlg.GetPath())
+ for proj, pf in sel:
+ if proj is not None:
+ proj_file.Add(proj)
+ self.write_proj_file(proj_file)
+ self.parent.application.SetPath("projection", dlg.GetPath())
+
+ dlg.Destroy()
+
+ def _OnRemove(self, event):
+ """Handler for the 'Remove' button
+
+ Remove any selected projection that came from the user's
+ ProjFile. If the user ProjFile was modified write it back to
+ disk.
+ """
+ sel = self.projection_list.selected_projections()
+ assert len(sel) != 0, "button should be disabled!"
+
+ modified = False
+ for proj, pf in sel:
+ if proj is not None and pf is self.__usrProjFile:
+ pf.Remove(proj)
+ modified = True
+
+ if modified:
+ self.write_proj_file(self.__usrProjFile)
+
+ def _OnShowEPSG(self, event):
+ """Handler for the EVT_CHECKBOX events from the EPSG check button
+
+ If the button is checked add the EPSG_PROJ_FILE to the list of
+ projfiles shown by the projection list. Otherwise remove it
+ """
+ proj_files = [self.load_user_proj(),
+ self.load_system_proj(DEFAULT_PROJ_FILE)]
+ if self.check_epsg.IsChecked():
+ proj_files.append(self.load_system_proj(EPSG_PROJ_FILE))
+ if self.check_epsg_depr.IsChecked():
+ proj_files.append(self.load_system_proj(EPSG_DEPRECATED_PROJ_FILE))
+ self.projection_list.SetProjFiles(proj_files)
+
+ def _OnProjName(self, event):
+ self.__VerifyButtons()
+
+ def __ShowError(self, filename, errstr):
+ wx.MessageDialog(self,
+ _("The following error occured:\n") +
+ filename + "\n" + errstr,
+ _("Error"), wx.OK | wx.ICON_ERROR).ShowModal()
+
+ def __VerifyButtons(self):
+ """Update button sensitivity"""
+
+ num_sel = self.projection_list.GetSelectedItemCount()
+
+ self.button_import.Enable(True)
+ self.button_export.Enable(True)
+ self.button_save.Enable(True)
+ self.button_remove.Enable(True)
+
+ self.edit_box.Enable(True)
+
+ for ctrl in [self.button_import,
+ self.button_export,
+ self.button_remove,
+ self.button_save,
+ self.button_add,
+ self.projchoice,
+ self.projname,
+ self.edit_box]:
+ ctrl.Enable(True)
+
+ if self.curProjPanel is not None:
+ self.curProjPanel.Enable(True)
+
+ if num_sel == 0:
+ self.button_import.Enable(True)
+ self.button_export.Enable(False)
+ self.button_remove.Enable(False)
+ self.button_save.Enable(False)
+
+ elif num_sel == 1:
+
+ selection = self.projection_list.selected_projections()
+ proj, projFile = selection[0]
+
+ self.button_save.Enable(len(self.projname.GetValue()) > 0)
+ self.button_add.Enable(len(self.projname.GetValue()) > 0)
+
+ if proj is None:
+ # <None> is selected
+ for ctrl in [self.button_export,
+ self.button_remove,
+ self.button_save,
+ self.button_add,
+ self.projchoice,
+ self.projname]:
+ ctrl.Enable(False)
+
+ if self.curProjPanel is not None:
+ self.curProjPanel.Enable(False)
+
+ elif proj is self.originalProjection:
+ self.button_remove.Enable(False)
+
+ if projFile is None:
+ self.button_save.Enable(False)
+
+ else:
+ self.edit_box.Enable(False)
+
+ def proj_selection_changed(self, projs):
+ """Subscribed to the projection_list's PROJ_SELECTION_CHANGED message
+
+ Update the dialog to reflect the new selection.
+ """
+ if len(projs) == 0:
+ self.projfilepath.SetLabel(_("No Projections selected"))
+ elif len(projs) == 1:
+ proj, projfile = projs[0]
+ if proj is None:
+ # user selected <None>
+ self.projname.Clear()
+ self.projfilepath.SetLabel("")
+ else:
+ if projfile is not None:
+ filename = os.path.basename(projfile.GetFilename())
+ self.projfilepath.SetLabel(_("Source of Projection: %s")
+ % filename)
+ else:
+ # only None if the currently used projection is selected
+ self.projfilepath.SetLabel("")
+
+ self.projname.SetValue(proj.Label())
+
+ myProjType = proj.GetParameter("proj")
+ i = 0
+ for projType, name, cls in self.projection_panel_defs:
+ if myProjType == projType:
+ self.projchoice.Enable(True)
+ self.projchoice.SetSelection(i + 1)
+ self.__DoOnProjChoice()
+
+ #
+ # self.curProjPanel should not be null
+ # after a call to __DoOnProjChoice
+ #
+ assert self.curProjPanel is not None
+
+ self.curProjPanel.SetProjection(proj)
+ break
+ i += 1
+ else:
+ self.projchoice.Select(0)
+ self.projchoice.Disable()
+ self._show_proj_panel(UnknownProjPanel)
+ assert self.curProjPanel is not None
+ self.curProjPanel.SetProjection(proj)
+ else:
+ self.projfilepath.SetLabel(_("Multiple Projections selected"))
+
+ self.__VerifyButtons()
+
+ def _OnProjChoice(self, event):
+ self.__DoOnProjChoice()
+
+ def __DoOnProjChoice(self):
+ """Create and layout a projection panel based on the selected
+ projection type.
+
+ This is necessary to have in seperate method since calls to
+ wxChoice.SetSelection() do not trigger an event.
+
+ At the end of this method self.curProjPanel will not be None
+ if there was a item selected.
+ """
+ choice = self.projchoice
+
+ sel = choice.GetSelection()
+ if sel != -1:
+ proj_type = choice.GetClientData(sel)
+ for t, name, cls in self.projection_panel_defs:
+ if t == proj_type:
+ self._show_proj_panel(cls)
+ break
+ # FIXME: what to do if sel == -1?
+
+ def _show_proj_panel(self, panel_class):
+ """Show the panel as the projection panel"""
+ if panel_class is UnknownProjPanel:
+ self.button_ok.Disable()
+ self.button_try.Disable()
+ self.edit_box.Disable()
+ self.nbsizer.Activate(self.unknown_projection_panel)
+ self.curProjPanel = self.unknown_projection_panel
+ else:
+ self.button_ok.Enable(True)
+ self.button_try.Enable(True)
+ self.edit_box.Enable(True)
+ self.unknown_projection_panel.Hide()
+ for panel in self.projection_panels:
+ if panel.__class__ is panel_class:
+ self.nbsizer.Activate(panel)
+ self.curProjPanel = panel
+
+ def __SetProjection(self):
+ """Set the receiver's projection."""
+
+ #
+ # save the original projection only once in case
+ # we try to apply several different projections
+ #
+ self.receiver.SetProjection(self.__GetProjection())
+
+ def __GetProjection(self):
+ """Return a suitable Projection object based on the current
+ state of the dialog box selections.
+
+ Could be None.
+ """
+
+ assert self.projection_list.GetSelectedItemCount() < 2, \
+ "button should be disabled"
+
+ sel = self.projection_list.selected_projections()
+ if len(sel) == 1:
+ if sel[0][0] is None:
+ # <None> is selected
+ return None
+
+ # self.curProjPanel should always contain the most relevant data
+ # for a projection
+ if self.curProjPanel is not None:
+ parameters = self.curProjPanel.GetParameters()
+ if parameters is not None:
+ return Projection(parameters, self.projname.GetValue())
+
+ return None
+
+ def load_user_proj(self):
+ """Return the user's ProjFile
+
+ If the file has not yet been loaded by the dialog, load it first
+ with get_user_proj_file and cache it in self.__usrProjFile.
+
+ Show a busy cursor while loading the file.
+
+ If the file is not available, leave a note to the console.
+ """
+ if self.__usrProjFile is None:
+ ThubanBeginBusyCursor()
+ try:
+ projfile, warnings = get_user_proj_file()
+ if warnings:
+ sys.stderr.write("".join(warnings))
+ sys.stderr.write("\n")
+ self.__usrProjFile = projfile
+ finally:
+ ThubanEndBusyCursor()
+ return self.__usrProjFile
+
+ def load_system_proj(self, name):
+ """Load the system ProjFile with the given name.
+
+ If the file has not been loaded yet, load it first with
+ get_system_proj_file and put it into the cache. The name is
+ simply forwarded to get_system_proj_file.
+
+ Show a busy cursor while loading the file.
+ """
+ if name not in self._sys_proj_files:
+ ThubanBeginBusyCursor()
+ try:
+ projfile, warnings = get_system_proj_file(name)
+ self.show_warnings(_("Warnings"), projfile.GetFilename(),
+ warnings)
+ self._sys_proj_files[name] = projfile
+ finally:
+ ThubanEndBusyCursor()
+ return self._sys_proj_files[name]
+
+ def write_proj_file(self, proj_file):
+ """Write the ProjFile object proj_file back to its file
+
+ Show a busy cursor while writing and if an error occurs show a
+ dialog with the error message.
+ """
+ try:
+ ThubanBeginBusyCursor()
+ try:
+ write_proj_file(proj_file)
+ finally:
+ ThubanEndBusyCursor()
+ except IOError, (errno, errstr):
+ self.__ShowError(proj_file.GetFilename(), errstr)
+
+
+
+class ProjPanel(wx.Panel):
+ """Base class for all projection panels."""
+
+ def __init__(self, parent):
+ wx.Panel.__init__(self, parent, -1)
+
+ self.__ellps = wx.Choice(self, -1)
+ self.ellpsData = [("", _("<Unknown>")),
+ ("airy" , _("Airy")),
+ ("bessel", _("Bessel 1841")),
+ ("clrk66", _("Clarke 1866")),
+ ("clrk80", _("Clarke 1880")),
+ ("GRS80" , _("GRS 1980 (IUGG, 1980)")),
+ ("intl" , _("International 1909 (Hayford)")),
+ ("WGS84" , _("WGS 84"))]
+
+ for tag, name in self.ellpsData:
+ self.__ellps.Append(name, tag)
+
+ self.__ellps.SetSelection(0)
+
+ def _DoLayout(self, childPanel = None):
+
+ panelSizer = wx.BoxSizer(wx.VERTICAL)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(wx.StaticText(self, -1, _("Ellipsoid:")), 0,
+ wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ sizer.Add(self.__ellps, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ panelSizer.Add(sizer, 0, wx.ALL|wx.EXPAND, 4)
+
+ if childPanel is not None:
+ panelSizer.Add(childPanel, 0, wx.EXPAND, 0)
+
+ self.SetAutoLayout(1)
+ self.SetSizer(panelSizer)
+ panelSizer.Fit(self)
+ panelSizer.SetSizeHints(self)
+ self.Layout()
+
+ def SetProjection(self, proj):
+ if proj is not None:
+ param = proj.GetParameter("ellps")
+ i = 0
+ for tag, name in self.ellpsData:
+ if param == tag:
+ self.__ellps.SetSelection(i)
+ return # returning early!
+ i += 1
+
+ #
+ # if proj is none, or the parameter couldn't be found...
+ #
+ self.__ellps.SetSelection(0)
+
+ def GetParameters(self):
+ ellps = self.__ellps.GetSelection()
+ if ellps > 0:
+ return ["ellps=" + self.__ellps.GetClientData(ellps)]
+ return []
+
+
+ID_TMPANEL_LAT = 4001
+ID_TMPANEL_LONG = 4002
+ID_TMPANEL_FASLE_EAST = 4003
+ID_TMPANEL_FALSE_NORTH = 4004
+ID_TMPANEL_SCALE = 4005
+
+class UnknownProjPanel(ProjPanel):
+
+ """Panel for unknown projection types"""
+
+ def __init__(self, parent, receiver):
+ ProjPanel.__init__(self, parent)
+
+ self.__text = _("Thuban does not know the parameters\n"
+ "for the current projection and cannot\n"
+ "display a configuration panel.\n\n"
+ "The unidentified set of parameters is:\n\n")
+
+ self.__textbox = wx.TextCtrl(self, -1, self.__text, size=(100,200),
+ style=wx.TE_READONLY|wx.TE_MULTILINE|wx.TE_LINEWRAP)
+ self._DoLayout()
+
+ def _DoLayout(self):
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ sizer.Add(self.__textbox, 0, wx.ALL|wx.EXPAND, 4)
+
+ ProjPanel._DoLayout(self, sizer)
+
+ def GetProjName(self):
+ return "Unknown"
+
+ def SetProjection(self, proj):
+ """Append the available parameters to the info text."""
+ text = self.__text
+ for param in proj.GetAllParameters():
+ text = text + '%s\n' % param
+ self.__textbox.SetValue(text)
+
+ def GetParameters(self):
+ return None
+
+class TMPanel(ProjPanel):
+ """Projection panel for Transverse Mercator."""
+
+ def __init__(self, parent, receiver):
+ ProjPanel.__init__(self, parent)
+
+ self.__latitude = wx.TextCtrl(self, ID_TMPANEL_LAT)
+ self.__longitude = wx.TextCtrl(self, ID_TMPANEL_LONG)
+ self.__falseEast = wx.TextCtrl(self, ID_TMPANEL_FASLE_EAST)
+ self.__falseNorth = wx.TextCtrl(self, ID_TMPANEL_FALSE_NORTH)
+ self.__scale = wx.TextCtrl(self, ID_TMPANEL_SCALE)
+
+ self._DoLayout()
+
+ def _DoLayout(self):
+
+ sizer = wx.FlexGridSizer(4, 2, 0, 0)
+ sizer.Add(wx.StaticText(self, -1, _("Latitude:")), 0, wx.ALL, 4)
+ sizer.Add(self.__latitude, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Longitude:")), 0, wx.ALL, 4)
+ sizer.Add(self.__longitude, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("False Easting:")), 0, wx.ALL, 4)
+ sizer.Add(self.__falseEast, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("False Northing:")), 0, wx.ALL, 4)
+ sizer.Add(self.__falseNorth, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Scale Factor:")), 0, wx.ALL, 4)
+ sizer.Add(self.__scale, 0, wx.ALL, 4)
+
+ ProjPanel._DoLayout(self, sizer)
+
+ def GetProjName(self):
+ return _("Transverse Mercator")
+
+ def SetProjection(self, proj):
+ ProjPanel.SetProjection(self, proj)
+
+ self.__latitude.SetValue(proj.GetParameter("lat_0"))
+ self.__longitude.SetValue(proj.GetParameter("lon_0"))
+ self.__falseEast.SetValue(proj.GetParameter("x_0"))
+ self.__falseNorth.SetValue(proj.GetParameter("y_0"))
+ self.__scale.SetValue(proj.GetParameter("k"))
+
+ ProjPanel.SetProjection(self, proj)
+
+ def GetParameters(self):
+ params = ["proj=tmerc",
+ "lat_0=" + self.__latitude.GetValue(),
+ "lon_0=" + self.__longitude.GetValue(),
+ "x_0=" + self.__falseEast.GetValue(),
+ "y_0=" + self.__falseNorth.GetValue(),
+ "k=" + self.__scale.GetValue()]
+ params.extend(ProjPanel.GetParameters(self))
+ return params
+
+ def Clear(self):
+ self.__latitude.Clear()
+ self.__longitude.Clear()
+ self.__falseEast.Clear()
+ self.__falseNorth.Clear()
+ self.__scale.Clear()
+
+ ProjPanel.Clear(self)
+
+ID_UTMPANEL_ZONE = 4001
+ID_UTMPANEL_SOUTH = 4002
+ID_UTMPANEL_PROP = 4003
+
+class UTMPanel(ProjPanel):
+ """Projection Panel for Universal Transverse Mercator."""
+
+ def __init__(self, parent, receiver):
+ ProjPanel.__init__(self, parent)
+
+ self.receiver = receiver
+
+ self.__zone = wx.SpinCtrl(self, ID_UTMPANEL_ZONE, "1", min=1, max=60)
+ self.__propButton = wx.Button(self, ID_UTMPANEL_PROP, _("Propose"))
+ self.__south = wx.CheckBox(self, ID_UTMPANEL_SOUTH,
+ _("Southern Hemisphere"))
+
+ self._DoLayout()
+
+ self.Bind(wx.EVT_BUTTON, self._OnPropose, id=ID_UTMPANEL_PROP)
+
+ def _DoLayout(self):
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ psizer = wx.BoxSizer(wx.HORIZONTAL)
+ psizer.Add(wx.StaticText(self, -1, _("Zone:")), 0, wx.ALL, 4)
+ psizer.Add(self.__zone, 0, wx.ALL, 4)
+ psizer.Add(self.__propButton, 0, wx.ALL, 4)
+ sizer.Add(psizer, 0, wx.ALL, 4)
+ sizer.Add(self.__south, 0, wx.ALL, 4)
+
+ ProjPanel._DoLayout(self, sizer)
+
+ def GetProjName(self):
+ return _("Universal Transverse Mercator")
+
+ def SetProjection(self, proj):
+ self.__zone.SetValue(int(proj.GetParameter("zone")))
+ self.__south.SetValue(proj.GetParameter("south") != "")
+ ProjPanel.SetProjection(self, proj)
+
+ def GetParameters(self):
+ params = ["proj=utm", "zone=" + str(self.__zone.GetValue())]
+ if self.__south.IsChecked():
+ params.append("south")
+
+ params.extend(ProjPanel.GetParameters(self))
+ return params
+
+ def Clear(self):
+ self.__zone.SetValue(1)
+ self.__south.SetValue(False)
+ ProjPanel.Clear(self)
+
+ def _OnPropose(self, event):
+ """Call the propose dialog.
+ If the receiver (e.g. the current map) has no bounding box,
+ inform the user accordingly.
+ """
+ bb = self.receiver.BoundingBox()
+ if bb is None:
+ dlg = wx.MessageDialog(self,
+ _("Can not propose: No bounding box found."),
+ _("Projection: Propose UTM Zone"),
+ wx.OK | wx.ICON_INFORMATION)
+ dlg.CenterOnParent()
+ result = dlg.ShowModal()
+ dlg.Destroy()
+ return
+
+ dlg = UTMProposeZoneDialog(self, self.receiver.BoundingBox())
+ if dlg.ShowModal() == wx.ID_OK:
+ self.__zone.SetValue(dlg.GetProposedZone())
+
+class LCCPanel(ProjPanel):
+ """Projection Panel for Lambert Conic Conformal."""
+
+ def __init__(self, parent, receiver):
+ ProjPanel.__init__(self, parent)
+
+ self.__fspLatitude = wx.TextCtrl(self, -1)
+ self.__sspLatitude = wx.TextCtrl(self, -1)
+ self.__meridian = wx.TextCtrl(self, -1)
+ self.__originLat = wx.TextCtrl(self, -1)
+ self.__falseEast = wx.TextCtrl(self, -1)
+ self.__falseNorth = wx.TextCtrl(self, -1)
+
+ self._DoLayout()
+
+ def _DoLayout(self):
+
+ sizer = wx.FlexGridSizer(6, 2, 0, 0)
+ sizer.Add(wx.StaticText(self, -1,
+ _("Latitude of first standard parallel:")))
+ sizer.Add(self.__fspLatitude, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1,
+ _("Latitude of second standard parallel:")))
+ sizer.Add(self.__sspLatitude, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Central Meridian:")))
+ sizer.Add(self.__meridian, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("Latitude of origin:")))
+ sizer.Add(self.__originLat, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("False Easting:")))
+ sizer.Add(self.__falseEast, 0, wx.ALL, 4)
+ sizer.Add(wx.StaticText(self, -1, _("False Northing:")))
+ sizer.Add(self.__falseNorth, 0, wx.ALL, 4)
+
+ ProjPanel._DoLayout(self, sizer)
+
+ def GetProjName(self):
+ return _("Lambert Conic Conformal")
+
+ def SetProjection(self, proj):
+ self.__fspLatitude.SetValue(proj.GetParameter("lat_1"))
+ self.__sspLatitude.SetValue(proj.GetParameter("lat_2"))
+ self.__originLat.SetValue(proj.GetParameter("lat_0"))
+ self.__meridian.SetValue(proj.GetParameter("lon_0"))
+ self.__falseEast.SetValue(proj.GetParameter("x_0"))
+ self.__falseNorth.SetValue(proj.GetParameter("y_0"))
+
+ ProjPanel.SetProjection(self, proj)
+
+ def GetParameters(self):
+ params = ["proj=lcc",
+ "lat_1=" + self.__fspLatitude.GetValue(),
+ "lat_2=" + self.__sspLatitude.GetValue(),
+ "lat_0=" + self.__originLat.GetValue(),
+ "lon_0=" + self.__meridian.GetValue(),
+ "x_0=" + self.__falseEast.GetValue(),
+ "y_0=" + self.__falseNorth.GetValue()]
+
+ params.extend(ProjPanel.GetParameters(self))
+ return params
+
+ def Clear(self):
+ self.__fspLatitude.Clear()
+ self.__sspLatitude.Clear()
+ self.__originLat.Clear()
+ self.__meridian.Clear()
+ self.__falseEast.Clear()
+ self.__falseNorth.Clear()
+
+ ProjPanel.Clear(self)
+
+class GeoPanel(ProjPanel):
+ """Projection Panel for a Geographic Projection."""
+
+ def __init__(self, parent, receiver):
+ ProjPanel.__init__(self, parent)
+
+ self.__choices = [(_("Degrees"), "0.017453"),
+ (_("Radians"), "1")]
+
+ self.__scale = wx.Choice(self, -1)
+ for choice, value in self.__choices:
+ self.__scale.Append(choice, value)
+
+ self._DoLayout()
+
+ def GetProjName(self):
+ return _("Geographic")
+
+ def SetProjection(self, proj):
+ value = proj.GetParameter("to_meter")
+ for i in range(len(self.__choices)):
+ choice, data = self.__choices[i]
+ if value == data:
+ self.__scale.SetSelection(i)
+ ProjPanel.SetProjection(self, proj)
+
+ def GetParameters(self):
+ params = ["proj=latlong",
+ "to_meter=%s" % self.__scale.GetClientData(
+ self.__scale.GetSelection())]
+
+ params.extend(ProjPanel.GetParameters(self))
+ return params
+
+ def Clear(self):
+ ProjPanel.Clear(self)
+
+ def _DoLayout(self):
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ sizer.Add(wx.StaticText(self, -1, _("Source Data is in: ")),
+ 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+ sizer.Add(self.__scale, 1, wx.EXPAND|wx.ALL, 4)
+
+ self.__scale.SetSelection(0)
+
+ ProjPanel._DoLayout(self, sizer)
+
+
+ID_UTM_PROPOSE_ZONE_DIALOG_TAKE = 4001
+ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4002
+class UTMProposeZoneDialog(wx.Dialog):
+
+ """Propose a sensible Zone considering the current map extent."""
+
+ def __init__(self, parent, (x, y, x2, y2)):
+ wx.Dialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
+ wx.DefaultPosition, wx.Size(200, 100))
+ self.parent = parent
+ x = x + 180
+ x2 = x2 + 180
+ center = (x2 - x) / 2 + x
+ self.proposedZone = int(center / 6 + 1)
+ self.dialogLayout()
+
+ def dialogLayout(self):
+ topBox = wx.BoxSizer(wx.VERTICAL)
+
+ textBox = wx.BoxSizer(wx.VERTICAL)
+ textBox.Add(wx.StaticText(self, -1, _("The current map extent center "
+ "lies in UTM Zone")),
+ 0, wx.ALIGN_CENTER|wx.ALL, 4)
+ textBox.Add(wx.StaticText(self, -1, str(self.proposedZone)),
+ 0, wx.ALIGN_CENTER|wx.ALL, 4)
+
+ topBox.Add(textBox, 1, wx.EXPAND|wx.ALL, 4)
+
+ buttonBox = wx.BoxSizer(wx.HORIZONTAL)
+ buttonBox.Add(wx.Button(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
+ _("Take")), 0, wx.ALL, 4)
+ buttonBox.Add(wx.Button(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
+ _("Cancel")), 0, wx.ALL, 4)
+ topBox.Add(buttonBox, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
+ self.Bind(wx.EVT_BUTTON, self.OnTake, id=ID_UTM_PROPOSE_ZONE_DIALOG_TAKE)
+ self.Bind(wx.EVT_BUTTON, self.OnCancel, id=ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(topBox)
+ topBox.Fit(self)
+ topBox.SetSizeHints(self)
+
+ def OnTake(self, event):
+ self.EndModal(wx.ID_OK)
+
+ def OnCancel(self, event):
+ self.EndModal(wx.ID_CANCEL)
+
+ def GetProposedZone(self):
+ return self.proposedZone
Added: packages/thuban/branches/upstream/current/Thuban/UI/projlist.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/projlist.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/projlist.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,241 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""List control for projections"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: projlist.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import wx
+
+from Thuban import _
+
+from Thuban.Lib.connector import Publisher
+
+from Thuban.Model.messages import PROJECTION_ADDED, PROJECTION_REMOVED, \
+ PROJECTION_REPLACED
+
+
+PROJ_SELECTION_CHANGED = "PROJ_SELECTION_CHANGED"
+
+
+class ProjectionList(wx.ListCtrl, Publisher):
+
+ """A ListCtrl that shows a list of projections
+
+ The list control is effectively a view on several ProjFile instances
+ and a specific 'original' projection (e.g. the projection of the
+ current map). The list control subscribes to the change messages of
+ the ProjFile instances to update the list whenever they change.
+
+ When the selection changes the instance sends a
+ PROJ_SELECTION_CHANGED message.
+ """
+
+ def __init__(self, parent, proj_files, orig_proj, ID = -1):
+ """Initialize the ProjectionList
+
+ Parameters:
+
+ parent -- The parent widget
+ proj_files -- a sequence of ProjFile objects
+ orig_proj -- The projection originally selected in the map/layer
+ """
+ wx.ListCtrl.__init__(self, parent, ID, style=wx.LC_REPORT|wx.LC_VIRTUAL)
+
+ self.InsertColumn(0, _("Available Projections"))
+ self.proj_files = proj_files
+ self._subscribe_proj_files()
+ self.orig_proj = orig_proj
+ self.projections = []
+ self.proj_map = {}
+ self.needs_update = False
+ self.update_projections()
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.Bind(wx.EVT_LEFT_UP, self.mouse_left_up)
+ self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.item_selected, id=self.GetId())
+ self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.item_deselected, id=self.GetId())
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+ def __del__(self):
+ wx.ListCtrl.__del__()
+ Publisher.__del__()
+
+ def _subscribe_proj_files(self):
+ """Subscribe to the messages of self.proj_files"""
+ for pf in self.proj_files:
+ pf.Subscribe(PROJECTION_ADDED, self.pf_projection_added)
+ pf.Subscribe(PROJECTION_REMOVED, self.pf_projection_removed)
+ pf.Subscribe(PROJECTION_REPLACED, self.pf_projection_replaced)
+
+ def _unsubscribe_proj_files(self):
+ """Unsubscribe from the messages subscribed to in _subscribe_proj_files
+ """
+ for pf in self.proj_files:
+ pf.Unsubscribe(PROJECTION_ADDED, self.pf_projection_added)
+ pf.Unsubscribe(PROJECTION_REMOVED, self.pf_projection_removed)
+ pf.Unsubscribe(PROJECTION_REPLACED, self.pf_projection_replaced)
+
+ def Destroy(self):
+ self._unsubscribe_proj_files()
+ # Call wxListCtrl's method last because afterwards self is not
+ # an instance of ProjectionList anymore as wxPython replaces
+ # self.__class__ with its dead object class
+ Publisher.Destroy(self)
+ wx.ListCtrl.Destroy(self)
+
+ def update_on_idle(self):
+ self.needs_update = True
+
+ def OnIdle(self, evt):
+ if self.needs_update:
+ self.needs_update = False
+ self.update_projections()
+ evt.Skip()
+
+ def update_projections(self):
+ """Update the internal list of projection information"""
+
+ # Remember which projections are selected so that we can select
+ # them again after the update
+ selection = {}
+ for p in self.selected_projections():
+ selection[id(p[0])] = 1
+ old_length = len(self.projections)
+
+ # Build the new projection list
+ projections = [(_("<None>"), None, None)]
+ for pf in self.proj_files:
+ for p in pf.GetProjections():
+ projections.append((p.Label(), p, pf))
+ if self.orig_proj is not None:
+ projections.append((_("%s (current)") % self.orig_proj.Label(),
+ self.orig_proj, None))
+ self.projections = projections
+ self.projections.sort()
+
+ # Deselect all items with indices higher than the new length
+ # before settign the new item count This is a work-around for a
+ # bug in the listctrl which doesn't updat the selection count
+ # correctly in a call to SetItemCount if items have been
+ # selected with indices higher than the new count.
+ if len(self.projections) < old_length:
+ for i in xrange(len(self.projections), old_length):
+ self.SetItemState(i, 0, wx.LIST_STATE_SELECTED)
+
+ self.SetItemCount(len(self.projections))
+
+ # Reselect the projections that had been selected before.
+ get = selection.get
+ count = 0
+ for i in xrange(len(self.projections)):
+ p = self.projections[i][1]
+ if get(id(p)):
+ state = wx.LIST_STATE_SELECTED
+ count += 1
+ else:
+ state = 0
+ self.SetItemState(i, state, wx.LIST_STATE_SELECTED)
+
+ # If the selection changed send a PROJ_SELECTION_CHANGED message
+ if count != len(selection):
+ self._issue_proj_selection_changed()
+
+ def pf_projection_added(self, proj):
+ """Subscribed to the projfile's PROJECTION_ADDED messages
+
+ Request an update the projection list in idle time.
+ """
+ self.update_on_idle()
+
+ def pf_projection_removed(self, proj):
+ """Subscribed to the projfile's PROJECTION_REMOVED messages
+
+ Request an update the projection list in idle time.
+ """
+ self.update_on_idle()
+
+ def pf_projection_replaced(self, old, new):
+ """Subscribed to the projfile's PROJECTION_REPLACED messages
+
+ Request an update the projection list in idle time.
+ """
+ self.update_on_idle()
+
+ def OnSize(self, evt):
+ self.SetColumnWidth(0, evt.GetSize().width)
+ evt.Skip()
+
+ def SelectProjection(self, proj):
+ """Select the projection and deselect all others."""
+ # Set both the wxLIST_STATE_SELECTED and wxLIST_STATE_FOCUSED
+ # flags on the newly selected item. If only
+ # wxLIST_STATE_SELECTED is set, some other item is focused and
+ # the first time the focus is moved with the keyboard the
+ # selection moves in unexpected ways.
+ state = wx.LIST_STATE_SELECTED|wx.LIST_STATE_FOCUSED
+ for i in range(len(self.projections)):
+ p = self.projections[i][1]
+ self.SetItemState(i, p is proj and state or 0, state)
+
+ def ClearSelection(self):
+ """Deselect all projections."""
+ for i in range(len(self.projections)):
+ self.SetItemState(i, 0, wx.LIST_STATE_SELECTED)
+
+ def SetProjFiles(self, proj_files):
+ """Set the projfile objects whose projections are shown in the list"""
+ self._unsubscribe_proj_files()
+ self.proj_files = proj_files
+ self._subscribe_proj_files()
+ self.update_projections()
+
+ def OnGetItemText(self, item, col):
+ """Callback for the virtual ListCtrl mode"""
+ return self.projections[item][0]
+
+ def OnGetItemAttr(self, item):
+ """Callback for the virtual ListCtrl mode"""
+ return None
+
+ def OnGetItemImage(self, item):
+ """Callback for the virtual ListCtrl mode"""
+ return -1
+
+ def selected_projections(self):
+ """Return a list with all selected projection infos
+
+ The return value is a list of (proj, proj_file) pairs. proj_file
+ is the projection file object the projection was read from, if
+ any. Both proj and proj_file may be None, but if proj_file is
+ not None proj will also not be None.
+ """
+ return [self.projections[i][1:]
+ for i in range(len(self.projections))
+ if self.GetItemState(i, wx.LIST_STATE_SELECTED)]
+
+ def _issue_proj_selection_changed(self):
+ """Internal: Issue a PROJ_SELECTION_CHANGED message"""
+ self.issue(PROJ_SELECTION_CHANGED, self.selected_projections())
+
+ def item_selected(self, evt):
+ """Handler for EVT_LIST_ITEM_SELECTED"""
+ self._issue_proj_selection_changed()
+
+ def item_deselected(self, evt):
+ #"""Handler for EVT_LIST_ITEM_DESELECTED"""
+ self._issue_proj_selection_changed()
+
+ def mouse_left_up(self, evt):
+ """Handle EVT_LEFT_UP events. Issue a selection message.
+
+ It's not clear whether the selection really has changed but the
+ selection events send by the list ctrl don't cover selecting
+ ranges of items :(.
+ """
+ self._issue_proj_selection_changed()
Added: packages/thuban/branches/upstream/current/Thuban/UI/rasterlayerproperties.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/rasterlayerproperties.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/rasterlayerproperties.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,138 @@
+# Copyright (c) 2005 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Raster Layer Properties dialog"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: rasterlayerproperties.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import wx
+
+from Thuban import _
+from Thuban.UI.layerproperties import LayerProperties
+from Thuban.Model.resource import has_gdal_support, gdal_support_status
+
+from Thuban.version import versions
+
+ID_RB_MASK = 4002
+
+class RasterLayerProperties(LayerProperties):
+
+ def __init__(self, parent, name, layer, *args, **kw):
+ LayerProperties.__init__(self, parent, name, layer)
+
+ self.old_state = {}
+ self.old_state["mask_type"] = layer.MaskType()
+
+ LayerProperties.dialog_layout(self)
+
+ def dialog_layout(self, panel, panelBox):
+
+ info = self.layer.ImageInfo()
+
+ if info is None:
+ panelBox.Add(
+ wx.StaticText(panel, -1,
+ _("GDAL image information unavailable. See About box for details.")),
+ 0, wx.ALIGN_LEFT | wx.ALL, 4)
+ return
+
+
+ # Bounding Box
+ bbox = self.layer.LatLongBoundingBox()
+ if bbox is None:
+ text = _("Extent (lat-lon): None")
+ else:
+ text = _("Extent (lat-lon): (%g, %g, %g, %g)") % tuple(bbox)
+
+ panelBox.Add(wx.StaticText(panel, -1, text), 0, wx.ALIGN_LEFT|wx.ALL, 4)
+
+ rasterBox = wx.StaticBoxSizer(wx.StaticBox(panel, -1,
+ _("Image Properties")), wx.VERTICAL)
+
+
+ rasterBox.Add(
+ wx.StaticText(panel, -1,
+ _("Source: %s") % self.layer.GetImageFilename()),
+ 0, wx.ALIGN_LEFT | wx.ALL, 4)
+
+ infoBox = wx.BoxSizer(wx.HORIZONTAL)
+
+ nBands = info["nBands"]
+
+ self.usePalIndex = nBands == 1
+
+ infoBox.Add(
+ wx.StaticText(panel, -1, _("Driver: %s") % info["Driver"]),
+ 0, wx.ALIGN_LEFT | wx.RIGHT, 10)
+ infoBox.Add(
+ wx.StaticText(panel, -1, _("Size: %ix%i") % info["Size"]),
+ 0, wx.ALIGN_LEFT | wx.RIGHT, 10)
+ infoBox.Add(
+ wx.StaticText(panel, -1, _("Number of Bands: %i") % nBands),
+ 0, wx.ALIGN_LEFT | wx.RIGHT, 0)
+
+ rasterBox.Add(infoBox, 0, wx.ALIGN_LEFT|wx.ALL, 4)
+
+ # Mask
+
+ maskBox = wx.BoxSizer(wx.HORIZONTAL)
+
+ if versions['wxPython-tuple'] < (2,5,3):
+ choices = ["None", "Bitmap",
+ "Alpha (Not support by wxPython %s)" % \
+ versions['wxPython']]
+ else:
+ choices = ["None", "Bitmap", "Alpha"]
+
+ self.maskRadioBox = wx.RadioBox(panel, ID_RB_MASK, _("Mask Type"),
+ choices=choices)
+ #self.maskCB = wxCheckBox(panel, -1, _("Use Mask"))
+ maskBox.Add(self.maskRadioBox, 0, wx.RIGHT, 10)
+
+ self.opBox = wx.BoxSizer(wx.HORIZONTAL)
+ self.opSpinLabel = wx.StaticText(panel, -1, _("Opacity:"))
+ self.opBox.Add(self.opSpinLabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 4)
+ self.opSpin = wx.SpinCtrl(panel, -1,
+ str(self.layer.Opacity()*255),
+ initial = self.layer.Opacity()*255,
+ min=0, max=255)
+ self.opBox.Add(self.opSpin, 0, wx.ALL, 4)
+ maskBox.Add(self.opBox, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 4)
+
+ rasterBox.Add(maskBox, 0, wx.ALL, 4)
+ #rasterBox.Add(opBox, 0, wxALL, 4)
+
+ panelBox.Add(rasterBox, 1, wx.GROW | wx.ALL, 4)
+
+ self.maskRadioBox.SetSelection(self.old_state["mask_type"])
+
+ self.OnMaskSelect(None)
+
+ self.Bind(wx.EVT_RADIOBOX, self.OnMaskSelect, id=ID_RB_MASK)
+
+ def OnTry(self, event):
+ self.set_state()
+
+ def OnOK(self, event):
+ if self.set_state():
+ self.Close()
+
+ def OnRevert(self, event):
+ self.maskRadioBox.SetSelection(self.old_state["mask_type"])
+ self.set_state()
+
+ def OnMaskSelect(self, event):
+ allowOpacity = self.maskRadioBox.GetSelection()==2
+ self.opSpin.Enable(allowOpacity)
+ self.opSpinLabel.Enable(allowOpacity)
+
+ def set_state(self):
+ self.layer.SetMaskType(self.maskRadioBox.GetSelection())
+ self.layer.SetOpacity(self.opSpin.GetValue()/255.0)
+ return True
Added: packages/thuban/branches/upstream/current/Thuban/UI/renderer.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/renderer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/renderer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,488 @@
+# Copyright (c) 2001-2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2001-2003)
+# Jonathan Coles <jonathan at intevation.de> (2003)
+# Frank Koormann <frank.koormann at intevation.de> (2003)
+# Jan-Oliver Wagner <jan at intevation.de> (2003-2005)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+from __future__ import generators
+
+__version__ = "$Revision: 2712 $"
+# $Source$
+# $Id: renderer.py 2712 2006-10-15 23:27:05Z bernhard $
+
+import cStringIO
+
+import array
+
+import traceback
+
+from Thuban import _
+
+import wx
+
+from wxproj import draw_polygon_shape, draw_polygon_init
+
+from Thuban.UI.common import Color2wxColour
+from Thuban.UI.classifier import ClassDataPreviewer
+from Thuban.UI.scalebar import ScaleBar
+
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
+ SHAPETYPE_POINT, RAW_SHAPEFILE
+
+from Thuban.Model.color import Transparent
+import Thuban.Model.resource
+
+from baserenderer import BaseRenderer
+
+from math import floor
+
+from types import StringType
+
+from Thuban.version import versions
+
+if Thuban.Model.resource.has_gdal_support():
+ from gdalwarp import ProjectRasterFile
+
+verbose = 0 # whether to talk more on stdout
+
+# Map the strings used for the format parameter of the draw_raster_data
+# method to the appropriate wxWindows constants
+raster_format_map = {
+ "BMP": wx.BITMAP_TYPE_BMP,
+ "JPEG": wx.BITMAP_TYPE_JPEG,
+ "PNG": wx.BITMAP_TYPE_PNG,
+ "TIFF": wx.BITMAP_TYPE_TIF,
+ "GIF": wx.BITMAP_TYPE_GIF,
+ }
+
+class MapRenderer(BaseRenderer):
+
+ """Class to render a map onto a wxDC"""
+
+ TRANSPARENT_PEN = wx.TRANSPARENT_PEN
+ TRANSPARENT_BRUSH = wx.TRANSPARENT_BRUSH
+
+ def make_point(self, x, y):
+ return wx.Point(int(round(x)), int(round(y)))
+
+ def tools_for_property(self, prop):
+ fill = prop.GetFill()
+ if fill is Transparent:
+ brush = self.TRANSPARENT_BRUSH
+ else:
+ brush = wx.Brush(Color2wxColour(fill), wx.SOLID)
+
+ stroke = prop.GetLineColor()
+ if stroke is Transparent:
+ pen = self.TRANSPARENT_PEN
+ else:
+ pen = wx.Pen(Color2wxColour(stroke), prop.GetLineWidth(), wx.SOLID)
+ return pen, brush
+
+ def low_level_renderer(self, layer):
+ """Override inherited method to provide more efficient renderers
+
+ If the underlying data format is not a shapefile or the layer
+ contains points shapes, simply use what the inherited method
+ returns.
+
+ Otherwise, i.e. for arc and polygon use the more efficient
+ wxproj.draw_polygon_shape and its corresponding parameter
+ created with wxproj.draw_polygon_init.
+ """
+ if (layer.ShapeStore().RawShapeFormat() == RAW_SHAPEFILE
+ and layer.ShapeType() in (SHAPETYPE_ARC, SHAPETYPE_POLYGON)):
+ offx, offy = self.offset
+ x = lambda a, b, c, d: None
+ #return (True, x, None)
+ return (True, draw_polygon_shape,
+ draw_polygon_init(layer.ShapeStore().Shapefile(),
+ self.dc, self.map.projection,
+ layer.projection,
+ self.scale, -self.scale, offx, offy))
+ else:
+ return BaseRenderer.low_level_renderer(self, layer)
+
+ def label_font(self):
+ return wx.Font(int(round(self.resolution * 10)), wx.SWISS, wx.NORMAL,
+ wx.NORMAL)
+
+ def projected_raster_layer(self, layer, srcProj, dstProj, extents,
+ resolution, dimensions, options):
+ """Returns a raster layer image in projected space
+
+ Based on a given filename. This method must be implemented in
+ classes derived from BaseRenderer.
+ """
+
+ ret = None
+
+ if Thuban.Model.resource.has_gdal_support():
+
+ if versions['wxPython-tuple'] < (2,5,3):
+ options = options | 4 # INVERT_MASK_BITS
+ options = options & ~2 # ALPHA_MASK not supported
+
+ try:
+ if verbose > 0:
+ print "doing ProjectRasterFile '%s' -> '%s'" % \
+ (srcProj, dstProj)
+ print "extents:", extents, "resolution:", resolution
+ print "dimensions:", dimensions, "options:", options
+ ret = ProjectRasterFile(layer.GetImageFilename(),
+ srcProj, dstProj,
+ extents, resolution, dimensions,
+ options)
+ except (MemoryError, IOError, AttributeError, ValueError):
+ # Why does this catch AttributeError and ValueError?
+ # FIXME: The exception should be communicated to the user
+ # better.
+ traceback.print_exc()
+
+ return ret
+
+ def draw_raster_data(self, x,y, data, format = 'BMP', opacity=1.0):
+
+ mask = None
+ alpha = None
+ width = data[0]
+ height = data[1]
+ image_data, mask_data, alpha_data = data[2]
+
+ if versions['wxPython-tuple'] < (2,5,3):
+ alpha_data = None
+
+ if format == 'RAW':
+ image = wx.EmptyImage(width, height)
+ image.SetData(image_data)
+ if mask_data is not None:
+ mask = wx.BitmapFromBits(mask_data, width, height, 1)
+ mask = wx.Mask(mask)
+ elif alpha_data is not None:
+ # alpha_data is already in the right format
+ alpha = alpha_data
+
+ else:
+ stream = cStringIO.StringIO(image_data)
+ image = wx.ImageFromStream(stream, raster_format_map[format])
+
+ if mask_data is not None:
+ stream = cStringIO.StringIO(mask_data)
+ mask = wx.ImageFromStream(stream, raster_format_map[format])
+ mask = wx.Mask(wx.BitmapFromImage(mask, 1))
+ elif alpha_data is not None:
+ stream = cStringIO.StringIO(alpha_data)
+ alpha = wx.ImageFromStream(stream, raster_format_map[format])
+ alpha = alpha.GetData() #[:] # XXX: do we need to copy this?
+ elif image.HasAlpha():
+ alpha = image.GetAlphaData()
+
+ #
+ # scale down the alpha values the opacity level using a string
+ # translation table for efficiency.
+ #
+ if alpha is not None:
+ if opacity == 0:
+ return
+ elif opacity == 1:
+ a = alpha
+ else:
+ tr = [int(i*opacity) for i in range(256)]
+ table = array.array('B', tr).tostring()
+ a = alpha.translate(table)
+
+ image.SetAlphaData(a)
+
+ bitmap = wx.BitmapFromImage(image)
+
+ if mask is not None:
+ bitmap.SetMask(mask)
+
+ self.dc.DrawBitmap(bitmap, int(round(x)), int(round(y)), True)
+
+
+class ScreenRenderer(MapRenderer):
+
+ # On the screen we want to see only visible layers by default
+ honor_visibility = 1
+
+ def RenderMap(self, selected_layer, selected_shapes):
+ """Render the map.
+
+ Only the given region (a tuple in window coordinates as returned
+ by a wxrect's asTuple method) needs to be redrawn. Highlight the
+ shapes given by the ids in selected_shapes in the
+ selected_layer.
+ """
+ self.selected_layer = selected_layer
+ self.selected_shapes = selected_shapes
+ self.render_map()
+
+ def RenderMapIncrementally(self):
+ """Render the map.
+
+ Only the given region (a tuple in window coordinates as returned
+ by a wxrect's asTuple method) needs to be redrawn. Highlight the
+ shapes given by the ids in selected_shapes in the
+ selected_layer.
+ """
+ return self.render_map_incrementally()
+
+ def draw_selection_incrementally(self, layer, selected_shapes):
+ """Draw the selected shapes in a emphasized way (i.e.
+ with a special pen and brush.
+ The drawing is performed incrementally, that means every
+ n shapes, the user can have interactions with the map.
+ n is currently fixed to 500.
+
+ layer -- the layer where the shapes belong to.
+ selected_shapes -- a list of the shape-ids representing the
+ selected shapes for the given layer.
+ """
+ pen = wx.Pen(wx.BLACK, 3, wx.SOLID)
+ brush = wx.Brush(wx.BLACK, wx.CROSS_HATCH)
+
+ shapetype = layer.ShapeType()
+ useraw, func, param = self.low_level_renderer(layer)
+ args = (pen, brush)
+
+ # for point shapes we need to find out the properties
+ # to determine the size. Based on table and field,
+ # we can find out the properties for object - see below.
+ if shapetype == SHAPETYPE_POINT:
+ lc = layer.GetClassification()
+ field = layer.GetClassificationColumn()
+ table = layer.ShapeStore().Table()
+
+ count = 0
+ for index in selected_shapes:
+ count += 1
+ shape = layer.Shape(index)
+
+ # Get the size of the specific property for this
+ # point
+ if shapetype == SHAPETYPE_POINT:
+ if field is not None:
+ value = table.ReadValue(shape.ShapeID(), field)
+ group = lc.FindGroup(value)
+ size = group.GetProperties().GetSize()
+ else:
+ size = lc.GetDefaultGroup().GetProperties().GetSize()
+ args = (pen, brush, size)
+
+ if useraw:
+ data = shape.RawData()
+ else:
+ data = shape.Points()
+ func(param, data, *args)
+ if count % 500 == 0:
+ yield True
+
+ def layer_shapes(self, layer):
+ """Return the shapeids covered by the region that has to be redrawn
+
+ Call the layer's ShapesInRegion method to determine the ids so
+ that it can use the quadtree.
+ """
+ # FIXME: the quad-tree should be built from the projected
+ # coordinates not the lat-long ones because it's not trivial to
+ # determine an appropriate rectangle in lat-long for a given
+ # rectangle in projected coordinates which we have to start from
+ # here.
+ proj = self.map.projection
+ if proj is not None:
+ inverse = proj.Inverse
+ else:
+ inverse = None
+
+ scale = self.scale
+ offx, offy = self.offset
+ xs = []
+ ys = []
+ x, y, width, height = self.region
+ for winx, winy in ((x, y), (x + width, y),
+ (x + width, y + height), (x, y + height)):
+ px = (winx - offx) / scale
+ py = -(winy - offy) / scale
+ if inverse:
+ px, py = inverse(px, py)
+ xs.append(px)
+ ys.append(py)
+ left = min(xs)
+ right = max(xs)
+ top = max(ys)
+ bottom = min(ys)
+
+ return layer.ShapesInRegion((left, bottom, right, top))
+
+
+class ExportRenderer(ScreenRenderer):
+
+ honor_visibility = 1
+
+ def __init__(self, *args, **kw):
+ """Initialize the ExportRenderer.
+
+ In addition to all parameters of the the ScreenRender
+ constructor, this class requires and additional keyword argument
+ destination_region with a tuple (minx, miny, maxx, maxy) giving
+ the region in dc coordinates which is to contain the map.
+ """
+ self.destination_region = kw["destination_region"]
+ del kw["destination_region"]
+ ScreenRenderer.__init__(self, *args, **kw)
+
+ def RenderMap(self, selected_layer, selected_shapes):
+ """Render the map.
+
+ The rendering device has been specified during initialisation.
+ The device border distance was set in
+ Thuban.UI.viewport.output_transform().
+
+ RenderMap renders a frame set (one page frame, one around
+ legend/scalebar and one around the map), the map, the legend and
+ the scalebar on the given DC. The map is rendered with the
+ region displayed in the canvas view, centered on the area
+ available for map display.
+ """
+
+ self.selected_layer = selected_layer
+ self.selected_shapes = selected_shapes
+
+ # Get some dimensions
+ llx, lly, urx, ury = self.region
+ mminx, mminy, mmaxx, mmaxy = self.destination_region
+
+ # Manipulate the offset to position the map
+ offx, offy = self.offset
+ # 1. Shift to corner of map drawing area
+ offx = offx + mminx
+ offy = offy + mminy
+
+ # 2. Center the map on the map drawing area:
+ # region identifies the region on the canvas view:
+ # center of map drawing area - half the size of region: rendering origin
+ self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
+ self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
+
+ self.offset = (offx+self.shiftx, offy+self.shifty)
+ self.region = (llx + self.shiftx, lly + self.shifty, urx, ury)
+
+ # Draw the map
+ self.dc.BeginDrawing()
+ self.dc.DestroyClippingRegion()
+ self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
+ urx, ury)
+ self.render_map()
+ self.dc.EndDrawing()
+
+ # Draw the rest (frames, legend, scalebar)
+ self.dc.BeginDrawing()
+ self.dc.DestroyClippingRegion()
+
+ # Force the font for Legend drawing
+ font = wx.Font(self.resolution * 10, wx.SWISS, wx.NORMAL, wx.NORMAL)
+ self.dc.SetFont(font)
+
+ self.render_frame()
+ self.render_legend()
+ self.render_scalebar()
+ self.dc.EndDrawing()
+
+ def render_frame(self):
+ """Render the frames for map and legend/scalebar."""
+
+ dc = self.dc
+ dc.SetPen(wx.BLACK_PEN)
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+ # Dimension stuff
+ width, height = dc.GetSizeTuple()
+ mminx, mminy, mmaxx, mmaxy = self.destination_region
+
+ # Page Frame
+ dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
+
+ # Map Frame
+ llx, lly, urx, ury = self.region
+ dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
+
+ # Legend Frame
+ dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
+
+ dc.DestroyClippingRegion()
+ dc.SetClippingRegion(mmaxx+10,mminy,
+ (width-20) - (mmaxx+10), mmaxy-mminy)
+
+ def render_legend(self):
+ """Render the legend on the Map."""
+
+ previewer = ClassDataPreviewer()
+ dc = self.dc
+ dc.SetPen(wx.BLACK_PEN)
+ dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+ # Dimension stuff
+ width, height = dc.GetSizeTuple()
+ mminx, mminy, mmaxx, mmaxy = self.destination_region
+ textwidth, textheight = dc.GetTextExtent("0")
+ iconwidth = textheight
+ iconheight = textheight
+ stepy = textheight+3
+ dx = 10
+ posx = mmaxx + 10 + 5 # 10 pix distance mapframe/legend frame,
+ # 5 pix inside legend frame
+ posy = mminy + 5 # 5 pix inside legend frame
+
+ # Render the legend
+ dc.SetTextForeground(wx.BLACK)
+ if self.map.HasLayers():
+ layers = self.map.Layers()[:]
+ layers.reverse()
+ for l in layers:
+ if l.Visible():
+ # Render title
+ dc.DrawText(l.Title(), posx, posy)
+ posy+=stepy
+ if l.HasClassification():
+ # Render classification
+ clazz = l.GetClassification()
+ shapeType = l.ShapeType()
+ for g in clazz:
+ if g.IsVisible():
+ previewer.Draw(dc,
+ wx.Rect(posx+dx, posy,
+ iconwidth, iconheight),
+ g.GetProperties(), shapeType)
+ dc.DrawText(g.GetDisplayText(),
+ posx+2*dx+iconwidth, posy)
+ posy+=stepy
+
+ def render_scalebar(self):
+ """Render the scalebar."""
+
+ scalebar = ScaleBar(self.map)
+
+ # Dimension stuff
+ width, height = self.dc.GetSizeTuple()
+ mminx, mminy, mmaxx, mmaxy = self.destination_region
+
+ # Render the scalebar
+ scalebar.DrawScaleBar(self.scale, self.dc,
+ (mmaxx+10+5, mmaxy-25),
+ ((width-15-5) - (mmaxx+10+5),20)
+ )
+ # 10 pix between map and legend frame, 5 pix inside legend frame
+ # 25 pix from the legend frame bottom line
+ # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
+ # Height: 20
+
+class PrinterRenderer(ExportRenderer):
+
+ # Printing as well as Export / Screen display only the visible layer.
+ honor_visibility = 1
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/resource.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/resource.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/resource.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,32 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Acess to UI-related resources"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: resource.py 2700 2006-09-18 14:27:02Z dpinte $
+
+
+import os
+import Thuban
+
+import wx
+
+
+bitmapdir = os.path.join(Thuban.__path__[0], os.pardir, "Resources", "Bitmaps")
+bitmap_extensions = {wx.BITMAP_TYPE_XPM: ".xpm",
+ wx.BITMAP_TYPE_ANY: ""}
+
+def GetBitmapResource(file, type):
+ filename = os.path.join(bitmapdir, file) + bitmap_extensions[type]
+ return wx.Bitmap(filename, type)
+
+def GetImageResource(file, type):
+ filename = os.path.join(bitmapdir, file) + bitmap_extensions[type]
+ return wx.Image(filename, type)
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/scalebar.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/scalebar.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/scalebar.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,71 @@
+# Copyright (c) 2001, 2002 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+from Thuban import _
+from Thuban.Model.scalebar import deriveInterval, roundInterval
+from Thuban.Model.proj import PROJ_UNITS_METERS
+
+import wx
+
+class ScaleBar:
+
+ def __init__(self, map):
+ self.map = map
+
+ def DrawScaleBar(self, scale, dc, position, size):
+ """Draw a scalebar on a given DC"""
+
+ # Only draw a legend if the corresponding map has a layer
+ if self.map is not None \
+ and self.map.projection is not None \
+ and len(self.map.layers) > 0 \
+ and scale > 0.0:
+
+ # We have a projection, draw the scalebar in bw
+ BlackPen = wx.BLACK_PEN
+ BlackBrush = wx.BLACK_BRUSH
+ BlackText = wx.BLACK
+
+ # Get the dimension
+ width, height = size
+ posx, posy = position
+ l1width, l1height = dc.GetTextExtent("%d"%0)
+
+ # Make a first guess for the interval (to get the size we have
+ # to reserve for the labels)
+ interval, unit = deriveInterval(width, scale)
+ l2width, l2height = dc.GetTextExtent("%d %s"%(interval,unit))
+ width = width - 4.0 - l1width/2.0 -l2width/2.0
+
+ # Having precised the width now the final interval can be calculated
+ interval, unit = deriveInterval(width, scale)
+ interval, label = roundInterval(interval)
+
+ if interval > 0.0:
+ # We draw 2 rectangles with half the width
+ if unit == 'km':
+ width = int(interval*1000.0*scale/2)
+ else:
+ width = int(interval*scale/2)
+
+ dc.SetPen(BlackPen)
+
+ brush = wx.Brush(wx.WHITE, wx.SOLID)
+ dc.SetBrush(brush)
+ dc.DrawRectangle(posx+4,posy+2,width,8)
+
+ dc.SetBrush(BlackBrush)
+ dc.DrawRectangle(posx+width+4,posy+2,width,8)
+
+ dc.SetTextForeground(BlackText)
+ dc.DrawText("%d"%0, posx+ 4 - l1width/2, posy+12)
+
+ l2width, l2height = dc.GetTextExtent("%s %s"%(label, unit))
+ dc.DrawText("%s %s"%(interval, unit), posx+ 2*width+4 - l2width/2, posy + 12)
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/selection.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/selection.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/selection.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,168 @@
+# Copyright (c) 2001, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Selection handling
+"""
+
+__version__ = "$Revision: 2709 $"
+# $Source$
+# $Id: selection.py 2709 2006-10-03 09:34:51Z dpinte $
+
+from Thuban.Lib.connector import Publisher
+
+from messages import LAYER_SELECTED, SHAPES_SELECTED
+
+
+class Selection(Publisher):
+
+ """Manage the selection
+
+ The selection consists of a list of shape ids and the layer that
+ contains those shapes.
+
+ Messages issued by the selection:
+
+ LAYER_SELECTED -- A different layer has been selected or there was a
+ layer selected and the selection has been cleared.
+
+ Arguments: The newly selected layer or None if no
+ layer is selected.
+
+ SHAPES_SELECTED -- The set of selected shapes has changed.
+
+ Arguments: The newly selected layer or None if no
+ layer is selected and a list with ids of the
+ selected shapes. The list is empty if no shapes
+ are selected.
+ """
+
+ def __init__(self):
+ """Initialize the selection
+
+ Initially nothing is selected so the selected layer is None and
+ the list of selected shapes is empty.
+ """
+ self.layer = None
+ self.shapes = []
+
+ def issue_messages(self, issue_layer, issue_shape):
+ """Internal: Issue SHAPES_SELECTED and LAYER_SELECTED messages
+
+ If the issue_layer argument is true, issue a LAYER_SELECTED
+ message. If issue_shape is true issue a SHAPES_SELECTED message.
+ """
+ if issue_layer:
+ self.issue(LAYER_SELECTED, self.layer)
+ if issue_shape:
+ self.issue(SHAPES_SELECTED, self.layer, self.SelectedShapes())
+
+ def ClearSelection(self):
+ """Unselect the currently selected shapes if any.
+
+ If there was a layer selected before the call, send a
+ LAYER_SELECTED message. If there were selected shapes before the
+ call, send a SHAPES_SELECTED message as well.
+ """
+ issue_layer = self.layer is not None
+ issue_shape = len(self.shapes) > 0
+
+ self.layer = None
+ self.shapes = []
+ self.issue_messages(issue_layer, issue_shape)
+
+ def SelectedLayer(self):
+ """Return the selected layer. If no layer is selected return None"""
+ return self.layer
+
+ def HasSelectedLayer(self):
+ """Return true iff a layer is currently selected"""
+ return self.layer is not None
+
+ def SelectedShapes(self):
+ """Return the ids of the selected shapes as a list.
+
+ The list is sorted in ascending order. If no shapes are selected
+ the list is empty.
+ """
+ return self.shapes
+
+ def HasSelectedShapes(self):
+ """Return true iff at least one shape is selected."""
+ return len(self.shapes) > 0
+
+ def SelectLayer(self, layer):
+ """Select the given layer.
+
+ If the layer is the currently selected layer, do nothing.
+ Ortherwise, issue a LAYER_SELECTED message and if there were
+ shapes selected preciously issue a SHAPES_SELECTED message as
+ well.
+ """
+ if self.layer is not layer:
+ self.layer = layer
+ issue_shape = len(self.shapes) > 0
+ self.shapes = []
+ self.issue_messages(1, issue_shape)
+
+ def SelectShapes(self, layer, shapes, add = 0):
+ """Select the shapes given in the list shapes in the given layer.
+
+ If the optional keyword parameter add is true, add the selected
+ shapes to the currently selected shapes if layer is the already
+ selected layer if any. If add is false (the default) make the
+ shapes in shapes the selected shapes.
+
+ If a different layer is selected afterwards issue a
+ LAYER_SELECTED message. If the set of selected shapes has
+ changed afterwards issue a SHAPES_SELECTED message.
+ """
+ # Turn the shapes explicitly into a list. This main purpose
+ # is that we get a mutable sequence that we can modify in place.
+ shapes = list(shapes)
+ shapes.sort()
+
+ if self.layer is not layer:
+ # If the layer is differen we can ignore the add parameter
+ # and we have to issue both messages.
+ self.layer = layer
+ self.shapes = shapes
+ issue_layer = issue_shape = 1
+ else:
+ # If the layer is differen we have to merge the ids if add
+ # is true, and we won't have to issue the LAYER_SELECTED
+ # message.
+ issue_layer = 0
+ if add:
+ # Merge the ids by creating a dict with the ids in
+ # self.shapes and in shapes as the keys. The use the sorted
+ # keys of the dict as the new shapes list.
+ set = {}
+ for i in self.shapes:
+ set[i] = 1
+ for i in shapes:
+ set[i] = 1
+ shapes = set.keys()
+ shapes.sort()
+ if self.shapes != shapes:
+ self.shapes = shapes
+ issue_shape = 1
+ else:
+ issue_shape = 0
+
+ self.issue_messages(issue_layer, issue_shape)
+
+ def AddShapes(self, layer, shapes):
+ """Add the shapes on layer to the selection.
+
+ If the layer is the already selected layer, add the shape ids in
+ shapes to the already selected shapes.
+
+ If the layer is not the already selected layer, make the layer
+ and shapes the selected layer and shapes.
+ """
+ self.SelectShapes(layer, shapes)
Added: packages/thuban/branches/upstream/current/Thuban/UI/sizers.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/sizers.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/sizers.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,72 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Custom Sizers"""
+
+__version__ = "$Revision: 2700 $"
+# $Source$
+# $Id: sizers.py 2700 2006-09-18 14:27:02Z dpinte $
+
+import wx
+
+class NotebookLikeSizer(wx.PySizer):
+
+ """Similar to a wxNotebookSizer but doesn't need a real notebook
+ """
+
+ def __init__(self):
+ wx.PySizer.__init__(self)
+ self.item_dict = {}
+
+ def Add(self, item):
+ """Add the item to the sizer.
+
+ The children added with Add must must be an object that has
+ Show() and Hide() methods
+ """
+ wx.PySizer.Add(self, item)
+
+ def Activate(self, item):
+ """Activate the item.
+
+ Call this item's Show method and the Hide method of all other
+ items. The item must have been added to the sizer with Add.
+ """
+ for child in self.GetChildren():
+ window = child.GetWindow()
+ if window is item:
+ window.Show()
+ else:
+ window.Hide()
+
+ def RecalcSizes(self):
+ """Set all children to the current size of the sizer
+
+ This method is automatically called by the wxWindows sizer
+ mechanism.
+ """
+ pos = self.GetPosition()
+ size = self.GetSize()
+
+ for item in self.GetChildren():
+ item.SetDimension(pos, size)
+
+ def CalcMin(self):
+ """Return the maximum of the minimum sizes of the children.
+
+ This method is automatically called by the wxWindows sizer
+ mechanism.
+ """
+ widths = []
+ heights = []
+ for item in self.GetChildren():
+ size = item.CalcMin()
+ widths.append(size.width)
+ heights.append(size.height)
+ if widths:
+ return wx.Size(max(widths), max(heights))
+ return wx.Size(0, 0)
Added: packages/thuban/branches/upstream/current/Thuban/UI/tableview.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/tableview.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/tableview.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,648 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2718 $"
+
+import os.path
+
+from Thuban import _
+
+import wx
+from wx import grid
+
+from Thuban.Lib.connector import Publisher
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_DOUBLE, \
+ FIELDTYPE_STRING, table_to_dbf, table_to_csv
+from dialogs import ThubanFrame
+
+from messages import SHAPES_SELECTED, SESSION_REPLACED
+from Thuban.Model.messages import TABLE_REMOVED, MAP_LAYERS_REMOVED
+from Thuban.UI.common import ThubanBeginBusyCursor, ThubanEndBusyCursor
+
+wx_value_type_map = {FIELDTYPE_INT: grid.GRID_VALUE_NUMBER,
+ FIELDTYPE_DOUBLE: grid.GRID_VALUE_FLOAT,
+ FIELDTYPE_STRING: grid.GRID_VALUE_STRING}
+
+ROW_SELECTED = "ROW_SELECTED"
+
+QUERY_KEY = 'S'
+
+class DataTable(grid.PyGridTableBase):
+
+ """Wrapper around a Thuban table object suitable for a wxGrid"""
+
+ def __init__(self, table = None):
+ grid.PyGridTableBase.__init__(self)
+ self.num_cols = 0
+ self.num_rows = 0
+ self.columns = []
+ self.table = None
+ self.SetTable(table)
+
+ def SetTable(self, table):
+ self.table = table
+ self.num_cols = table.NumColumns()
+ self.num_rows = table.NumRows()
+
+ self.columns = []
+ for i in range(self.num_cols):
+ col = table.Column(i)
+ self.columns.append((col.name, wx_value_type_map[col.type]))
+
+ #
+ # required methods for the wxPyGridTableBase interface
+ #
+
+ def GetNumberRows(self):
+ return self.num_rows
+
+ def GetNumberCols(self):
+ return self.num_cols
+
+ def IsEmptyCell(self, row, col):
+ return 0
+
+ # Get/Set values in the table. The Python version of these
+ # methods can handle any data-type, (as long as the Editor and
+ # Renderer understands the type too,) not just strings as in the
+ # C++ version.
+ def GetValue(self, row, col):
+ try:
+ record = self.table.ReadRowAsDict(row, row_is_ordinal = 1)
+ except UnicodeError:
+ record = dict()
+ for (key, val) in self.table.ReadRowAsDict(row, \
+ row_is_ordinal = 1).items():
+ if isinstance(val, str):
+ record[key] = val.decode('iso-8859-1')
+ else:
+ record[key] = val
+ return record[self.columns[col][0]]
+
+ def SetValue(self, row, col, value):
+ pass
+
+ #
+ # Some optional methods
+ #
+
+ # Called when the grid needs to display labels
+ def GetColLabelValue(self, col):
+ return self.columns[col][0]
+
+ # Called to determine the kind of editor/renderer to use by
+ # default, doesn't necessarily have to be the same type used
+ # nativly by the editor/renderer if they know how to convert.
+ def GetTypeName(self, row, col):
+ return self.columns[col][1]
+
+ # Called to determine how the data can be fetched and stored by the
+ # editor and renderer. This allows you to enforce some type-safety
+ # in the grid.
+ def CanGetValueAs(self, row, col, typeName):
+ # perhaps we should allow conversion int->double?
+ return self.GetTypeName(row, col) == typeName
+
+ def CanSetValueAs(self, row, col, typeName):
+ return self.CanGetValueAs(row, col, typeName)
+
+
+ #
+ def RowIdToOrdinal(self, rowid):
+ """Return the ordinal of the row given by its id"""
+ return self.table.RowIdToOrdinal(rowid)
+
+ def RowOrdinalToId(self, ordinal):
+ """Return the id of the row given by its ordinal"""
+ return self.table.RowOrdinalToId(ordinal)
+
+
+class NullRenderer(grid.PyGridCellRenderer):
+
+ """Renderer that draws NULL as a gray rectangle
+
+ Other values are delegated to a normal renderer which is given as
+ the parameter to the constructor.
+ """
+
+ def __init__(self, non_null_renderer):
+ grid.PyGridCellRenderer.__init__(self)
+ self.non_null_renderer = non_null_renderer
+
+ def Draw(self, grid, attr, dc, rect, row, col, isSelected):
+ value = grid.table.GetValue(row, col)
+ if value is None:
+ dc.SetBackgroundMode(wx.SOLID)
+ dc.SetBrush(wx.Brush(wx.Colour(192, 192, 192), wx.SOLID))
+ dc.SetPen(wx.TRANSPARENT_PEN)
+ dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+ else:
+ self.non_null_renderer.Draw(grid, attr, dc, rect, row, col,
+ isSelected)
+
+ def GetBestSize(self, grid, attr, dc, row, col):
+ self.non_null_renderer.GetBestSize(grid, attr, dc, row, col)
+
+ def Clone(self):
+ return NullRenderer(self.non_null_renderer)
+
+
+class TableGrid(grid.Grid, Publisher):
+
+ """A grid view for a Thuban table
+
+ When rows are selected by the user the table issues ROW_SELECTED
+ messages. wx sends selection events even when the selection is
+ manipulated by code (instead of by the user) which usually lead to
+ ROW_SELECTED messages being sent in turn. Therefore sending messages
+ can be switched on and off with the allow_messages and
+ disallow_messages methods.
+ """
+
+ def __init__(self, parent, table = None):
+ grid.Grid.__init__(self, parent, -1)
+
+ self.allow_messages_count = 0
+
+ # keep track of which rows are selected.
+ self.rows = {}
+
+ self.table = DataTable(table)
+
+ # The second parameter means that the grid is to take ownership
+ # of the table and will destroy it when done. Otherwise you
+ # would need to keep a reference to it and call its Destroy
+ # method later.
+ self.SetTable(self.table, True)
+
+ #self.SetMargins(0,0)
+
+ # AutoSizeColumns would allow us to make the grid have optimal
+ # column widths automatically but it would cause a traversal of
+ # the entire table which for large .dbf files can take a very
+ # long time.
+ #self.AutoSizeColumns(False)
+
+ self.SetSelectionMode(grid.Grid.wxGridSelectRows)
+
+ self.ToggleEventListeners(True)
+ self.Bind(grid.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
+ self.Bind(grid.EVT_GRID_SELECT_CELL, self.OnSelectCell)
+
+ # Replace the normal renderers with our own versions which
+ # render NULL/None values specially
+ self.RegisterDataType(grid.GRID_VALUE_STRING,
+ NullRenderer(grid.GridCellStringRenderer()), None)
+ self.RegisterDataType(grid.GRID_VALUE_NUMBER,
+ NullRenderer(grid.GridCellNumberRenderer()), None)
+ self.RegisterDataType(grid.GRID_VALUE_FLOAT,
+ NullRenderer(grid.GridCellFloatRenderer()), None)
+
+ self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+ def OnDestroy(self, event):
+ Publisher.Destroy(self)
+
+ def SetTableObject(self, table):
+ self.table.SetTable(table)
+
+ def OnRangeSelect(self, event):
+ to_id = self.table.RowOrdinalToId
+ if self.handleSelectEvents:
+ self.rows = dict([(to_id(i), 0) for i in self.GetSelectedRows()])
+
+ # if we're selecting we need to include the selected range and
+ # make sure that the current row is also included, which may
+ # not be the case if you just click on a single row!
+ if event.Selecting():
+ for i in range(event.GetTopRow(), event.GetBottomRow() + 1):
+ self.rows[to_id(i)] = 0
+ self.rows[to_id(event.GetTopLeftCoords().GetRow())] = 0
+
+ self.issue(ROW_SELECTED, self.rows.keys())
+
+ event.Skip()
+
+ def OnSelectCell(self, event):
+ to_id = self.table.RowOrdinalToId
+ if self.handleSelectEvents:
+ self.issue(ROW_SELECTED,
+ [to_id(i) for i in self.GetSelectedRows()])
+ event.Skip()
+
+ def ToggleEventListeners(self, on):
+ self.handleSelectEvents = on
+
+ def GetNumberSelected(self):
+ return len(self.rows)
+
+ def disallow_messages(self):
+ """Disallow messages to be send.
+
+ This method only increases a counter so that calls to
+ disallow_messages and allow_messages can be nested. Only the
+ outermost calls will actually switch message sending on and off.
+ """
+ self.allow_messages_count += 1
+
+ def allow_messages(self):
+ """Allow messages to be send.
+
+ This method only decreases a counter so that calls to
+ disallow_messages and allow_messages can be nested. Only the
+ outermost calls will actually switch message sending on and off.
+ """
+ self.allow_messages_count -= 1
+
+ def issue(self, *args):
+ """Issue a message unless disallowed.
+
+ See the allow_messages and disallow_messages methods.
+ """
+ if self.allow_messages_count == 0:
+ Publisher.issue(self, *args)
+
+ def SelectRowById(self, rowid, do_select):
+ """Select row with the id rowid"""
+ self.SelectRow(self.table.RowIdToOrdinal(rowid), do_select)
+
+
+class LayerTableGrid(TableGrid):
+
+ """Table grid for the layer tables.
+
+ The LayerTableGrid is basically the same as a TableGrid but it's
+ selection is usually coupled to the selected object in the map.
+ """
+
+ def select_shapes(self, layer, shapes):
+ """Select the row corresponding to the specified shape and layer
+
+ If layer is not the layer the table is associated with do
+ nothing. If shape or layer is None also do nothing.
+ """
+ if layer is not None \
+ and layer.ShapeStore().Table() is self.table.table:
+
+ self.disallow_messages()
+ try:
+ self.ClearSelection()
+ if len(shapes) > 0:
+ # keep track of the lowest id so we can make it the
+ # first visible item
+ first = -1
+
+ to_ordinal = self.table.RowIdToOrdinal
+ for shape in shapes:
+ row = to_ordinal(shape)
+ self.SelectRow(row, True)
+ if row < first:
+ first = row
+
+ self.SetGridCursor(first, 0)
+ self.MakeCellVisible(first, 0)
+ finally:
+ self.allow_messages()
+
+
+class TableFrame(ThubanFrame):
+
+ """Frame that displays a Thuban table in a grid view"""
+
+ def __init__(self, parent, name, title, table):
+ ThubanFrame.__init__(self, parent, name, title)
+ self.panel = wx.Panel(self, -1)
+
+ self.table = table
+ self.grid = self.make_grid(self.table)
+ self.app = self.parent.application
+ self.app.Subscribe(SESSION_REPLACED, self.close_on_session_replaced)
+ self.session = self.app.Session()
+ self.session.Subscribe(TABLE_REMOVED, self.close_on_table_removed)
+
+ def OnDestroy(self, event):
+ """Extend inherited method to unsubscribe messages"""
+ self.app.Unsubscribe(SESSION_REPLACED, self.close_on_session_replaced)
+ self.session.Unsubscribe(TABLE_REMOVED, self.close_on_table_removed)
+ ThubanFrame.OnDestroy(self, event)
+
+ def make_grid(self, table):
+ """Return the table grid to use in the frame.
+
+ The default implementation returns a TableGrid instance.
+ Override in derived classes to use different grid classes.
+ """
+ return TableGrid(self, table)
+
+ def close_on_session_replaced(self, *args):
+ """Subscriber for the SESSION_REPLACED messages.
+
+ The table frame is tied to a session so close the window when
+ the session changes.
+ """
+ self.Close()
+
+ def close_on_table_removed(self, table):
+ """Subscriber for the TABLE_REMOVED messages.
+
+ The table frame is tied to a particular table so close the
+ window when the table is removed.
+ """
+ if table is self.table:
+ self.Close()
+
+
+ID_QUERY = 4001
+ID_EXPORT = 4002
+ID_COMBOVALUE = 4003
+ID_EXPORTSEL = 4004
+
+class QueryTableFrame(TableFrame):
+
+ """Frame that displays a table in a grid view and offers user actions
+ selection and export
+
+ A QueryTableFrame is TableFrame whose selection is connected to the
+ selected object in a map.
+ """
+
+ def __init__(self, parent, name, title, table):
+ TableFrame.__init__(self, parent, name, title, table)
+
+ self.combo_fields = wx.ComboBox(self.panel, -1, style=wx.CB_READONLY)
+ self.choice_comp = wx.Choice(self.panel, -1,
+ choices=["<", "<=", "==", "!=", ">=", ">"])
+ self.combo_value = wx.ComboBox(self.panel, ID_COMBOVALUE)
+ self.choice_action = wx.Choice(self.panel, -1,
+ choices=[_("Replace Selection"),
+ _("Refine Selection"),
+ _("Add to Selection")])
+
+ button_query = wx.Button(self.panel, ID_QUERY, _("Query"))
+ button_export = wx.Button(self.panel, ID_EXPORT, _("Export"))
+ button_exportSel = wx.Button(self.panel, ID_EXPORTSEL, _("Export Selection"))
+ button_close = wx.Button(self.panel, wx.ID_CLOSE, _("Close"))
+
+ self.CreateStatusBar()
+
+ self.grid.SetSize((400, 200))
+
+ self.combo_value.Append("")
+ for i in range(table.NumColumns()):
+ name = table.Column(i).name
+ self.combo_fields.Append(name)
+ self.combo_value.Append(name)
+
+ # assume at least one field?
+ self.combo_fields.SetSelection(0)
+ self.combo_value.SetSelection(0)
+ self.choice_action.SetSelection(0)
+ self.choice_comp.SetSelection(0)
+
+ self.grid.Reparent(self.panel)
+
+ self.UpdateStatusText()
+
+ topBox = wx.BoxSizer(wx.VERTICAL)
+
+ sizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1,
+ _("Selection")),
+ wx.HORIZONTAL)
+ sizer.Add(self.combo_fields, 1, wx.EXPAND|wx.ALL, 4)
+ sizer.Add(self.choice_comp, 0, wx.ALL, 4)
+ sizer.Add(self.combo_value, 1, wx.EXPAND|wx.ALL, 4)
+ sizer.Add(self.choice_action, 0, wx.ALL, 4)
+ sizer.Add(button_query, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4)
+ sizer.Add( (40, 20), 0, wx.ALL, 4)
+
+ topBox.Add(sizer, 0, wx.EXPAND|wx.ALL, 4)
+ topBox.Add(self.grid, 1, wx.EXPAND|wx.ALL, 0)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(button_export, 0, wx.ALL, 4)
+ sizer.Add(button_exportSel, 0, wx.ALL, 4)
+ sizer.Add( (60, 20), 1, wx.ALL|wx.EXPAND, 4)
+ sizer.Add(button_close, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
+ topBox.Add(sizer, 0, wx.ALL | wx.EXPAND, 4)
+
+ self.panel.SetAutoLayout(True)
+ self.panel.SetSizer(topBox)
+ topBox.Fit(self.panel)
+ topBox.SetSizeHints(self.panel)
+
+ panelSizer = wx.BoxSizer(wx.VERTICAL)
+ panelSizer.Add(self.panel, 1, wx.EXPAND, 0)
+ self.SetAutoLayout(True)
+ self.SetSizer(panelSizer)
+ panelSizer.Fit(self)
+ panelSizer.SetSizeHints(self)
+
+ self.grid.SetFocus()
+
+ self.Bind(wx.EVT_BUTTON, self.OnQuery, id=ID_QUERY)
+ self.Bind(wx.EVT_BUTTON, self.OnExport, id=ID_EXPORT)
+ self.Bind(wx.EVT_BUTTON, self.OnExportSel, id=ID_EXPORTSEL)
+ self.Bind(wx.EVT_BUTTON, self.OnClose, id=wx.ID_CLOSE)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown, self.grid)
+
+ self.grid.Subscribe(ROW_SELECTED, self.UpdateStatusText)
+
+ def UpdateStatusText(self, rows=None):
+ self.SetStatusText(_("%i rows (%i selected), %i columns")
+ % (self.grid.GetNumberRows(),
+ self.grid.GetNumberSelected(),
+ self.grid.GetNumberCols()))
+
+ def OnKeyDown(self, event):
+ """Catch query key from grid"""
+ if event.AltDown() and event.GetKeyCode() == ord(QUERY_KEY):
+ self.combo_fields.SetFocus()
+ self.combo_fields.refocus = True
+ else:
+ event.Skip()
+
+ def OnQuery(self, event):
+ ThubanBeginBusyCursor()
+ try:
+
+ text = self.combo_value.GetValue()
+ if self.combo_value.GetSelection() < 1 \
+ or self.combo_value.FindString(text) == -1:
+ value = text
+ else:
+ value = self.table.Column(text)
+
+ ids = self.table.SimpleQuery(
+ self.table.Column(self.combo_fields.GetStringSelection()),
+ self.choice_comp.GetStringSelection(),
+ value)
+
+ choice = self.choice_action.GetSelection()
+
+ #
+ # what used to be nice code got became a bit ugly because
+ # each time we select a row a message is sent to the grid
+ # which we are listening for and then we send further
+ # messages.
+ #
+ # now, we disable those listeners select everything but
+ # the first item, reenable the listeners, and select
+ # the first element, which causes everything to be
+ # updated properly.
+ #
+ if ids:
+ self.grid.ToggleEventListeners(False)
+
+ if choice == 0:
+ # Replace Selection
+ self.grid.ClearSelection()
+ elif choice == 1:
+ # Refine Selection
+ sel = self.get_selected()
+ self.grid.ClearSelection()
+ ids = filter(sel.has_key, ids)
+ elif choice == 2:
+ # Add to Selection
+ pass
+
+ #
+ # select the rows (all but the first)
+ #
+ firsttime = True
+ for id in ids:
+ if firsttime:
+ firsttime = False
+ else:
+ self.grid.SelectRowById(id, True)
+
+ self.grid.ToggleEventListeners(True)
+
+ #
+ # select the first row
+ #
+ if ids:
+ self.grid.SelectRowById(ids[0], True)
+
+ finally:
+ ThubanEndBusyCursor()
+
+ def doExport(self, onlySelected):
+
+ dlg = wx.FileDialog(self, _("Export Table To"), ".", "",
+ _("DBF Files (*.dbf)|*.dbf|") +
+ _("CSV Files (*.csv)|*.csv|") +
+ _("All Files (*.*)|*.*"),
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ type = os.path.basename(filename).split('.')[-1:][0]
+ dlg.Destroy()
+
+ if onlySelected:
+ records = self.grid.GetSelectedRows()
+ else:
+ records = None
+
+ if type.upper() == "DBF":
+ table_to_dbf(self.table, filename, records)
+ elif type.upper() == 'CSV':
+ table_to_csv(self.table, filename, records)
+ else:
+ dlg = wx.MessageDialog(None, "Unsupported format: %s" % type,
+ "Table Export", wx.OK|wx.ICON_WARNING)
+ dlg.ShowModal()
+ dlg.Destroy()
+ else:
+ dlg.Destroy()
+
+ def OnExport(self, event):
+ self.doExport(False)
+
+ def OnExportSel(self, event):
+ self.doExport(True)
+
+ def OnClose(self, event):
+ TableFrame.OnClose(self, event)
+
+ def get_selected(self):
+ """Return a dictionary of the selected rows.
+
+ The dictionary has the indexes as keys."""
+ to_id = self.table.RowOrdinalToId
+ return dict([(to_id(i), 0) for i in self.grid.GetSelectedRows()])
+
+
+class LayerTableFrame(QueryTableFrame):
+
+ """Frame that displays a layer table in a grid view
+
+ A LayerTableFrame is a QueryTableFrame whose selection is connected to the
+ selected object in a map.
+ """
+
+ def __init__(self, parent, name, title, layer, table):
+ QueryTableFrame.__init__(self, parent, name, title, table)
+ self.layer = layer
+ self.grid.Subscribe(ROW_SELECTED, self.rows_selected)
+ self.parent.Subscribe(SHAPES_SELECTED, self.select_shapes)
+ self.map = self.parent.Map()
+ self.map.Subscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
+
+ # if there is already a selection present, update the grid
+ # accordingly
+ sel = self.get_selected().keys()
+ for i in sel:
+ self.grid.SelectRowById(i, True)
+
+ def OnDestroy(self, event):
+ """Extend inherited method to unsubscribe messages"""
+ # There's no need to unsubscribe from self.grid's messages
+ # because it will get a DESTROY event too (since destroying the
+ # frame basically means that all child windows are also
+ # destroyed) and this it will clear all subscriptions
+ # automatically. It may even have been destroyed already (this
+ # does happen on w2000 for instance) so calling any of its
+ # methods here would be an error.
+ self.parent.Unsubscribe(SHAPES_SELECTED, self.select_shapes)
+ self.map.Unsubscribe(MAP_LAYERS_REMOVED, self.map_layers_removed)
+ QueryTableFrame.OnDestroy(self, event)
+
+ def make_grid(self, table):
+ """Override the derived method to return a LayerTableGrid.
+ """
+ return LayerTableGrid(self, table)
+
+ def get_selected(self):
+ """Override the derived method to return a dictionary of the selected
+ rows.
+ """
+ return dict([(i, 0) for i in self.parent.SelectedShapes()])
+
+ def select_shapes(self, layer, shapes):
+ """Subscribed to the SHAPES_SELECTED message.
+
+ If shapes contains exactly one shape id, select that shape in
+ the grid. Otherwise deselect all.
+ """
+ self.grid.select_shapes(layer, shapes)
+
+ def rows_selected(self, rows):
+ """Return the selected rows of the layer as they are returned
+ by Layer.SelectShapes().
+ """
+ if self.layer is not None:
+ self.parent.SelectShapes(self.layer, rows)
+
+ def map_layers_removed(self, *args):
+ """Receiver for the map's MAP_LAYERS_REMOVED message
+
+ Close the dialog if the layer whose table we're showing is not
+ in the map anymore.
+ """
+ if self.layer not in self.map.Layers():
+ self.Close()
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/tree.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/tree.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/tree.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,237 @@
+# Copyright (c) 2001, 2002, 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+__version__ = "$Revision: 2700 $"
+
+from types import StringType, UnicodeType
+
+import wx
+
+from Thuban import _
+from Thuban.UI.common import Color2wxColour
+
+from Thuban.Model.color import Color
+
+from Thuban.Model.messages import CHANGED
+from Thuban.Model.layer import Layer
+from Thuban.Model.map import Map
+
+from dialogs import NonModalNonParentDialog
+from messages import SESSION_REPLACED, LAYER_SELECTED
+
+BMP_SIZE = 15
+
+class SessionTreeCtrl(wx.TreeCtrl):
+
+ """Widget to display a tree view of the session.
+
+ The tree view is created recursively from the session object. The
+ tree view calls the session's TreeInfo method which should return a
+ pair (<title>, <item>) where <title> ist the title of the session
+ item in the tree view and <items> is a list of objects to use as the
+ children of the session in the tree view.
+
+ The items list can contain three types of items:
+
+ 1. a string. The string is used as the title for a leaf item in
+ the tree view.
+
+ 2. an object with a TreeInfo method. This method is called and
+ should return a pair just like the session's TreeInfo method.
+
+ 3. a pair (<title>, <item>) which is treated like the return
+ value of TreeInfo.
+ """
+
+ def __init__(self, parent, ID, mainwindow, app):
+
+ # Use the WANTS_CHARS style so the panel doesn't eat the Return key.
+ wx.TreeCtrl.__init__(self, parent, ID)
+
+ self.mainwindow = mainwindow
+ self.app = app
+ # boolean to indicate that we manipulate the selection ourselves
+ # so that we can ignore the selection events generated
+ self.changing_selection = 0
+
+ # Dictionary mapping layer id's to tree items
+ self.layer_to_item = {}
+
+ self.app.Subscribe(SESSION_REPLACED, self.session_changed)
+ self.mainwindow.Subscribe(LAYER_SELECTED, self.layer_selected)
+
+ # the session currently displayed in the tree
+ self.session = None
+
+
+ # pretend the session has changed to build the initial tree
+ self.session_changed()
+
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=self.GetId())
+
+ def unsubscribe_all(self):
+ if self.session is not None:
+ self.session.Unsubscribe(CHANGED, self.update_tree)
+ self.session = None
+ self.app.Unsubscribe(SESSION_REPLACED, self.session_changed)
+ self.mainwindow.Unsubscribe(LAYER_SELECTED, self.layer_selected)
+
+ def update_tree(self, *args):
+ """Clear and rebuild the tree"""
+ self.DeleteAllItems()
+ self.layer_to_item.clear()
+ self.image_list = wx.ImageList(BMP_SIZE, BMP_SIZE, False, 0)
+
+ bmp = wx.EmptyBitmap(BMP_SIZE, BMP_SIZE)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.SetBrush(wx.BLACK_BRUSH)
+ dc.Clear()
+ dc.SelectObject(wx.NullBitmap)
+
+ self.emptyImageIndex = \
+ self.image_list.AddWithColourMask(bmp, wx.Colour(0, 0, 0))
+
+ self.AssignImageList(self.image_list)
+
+ session = self.app.session
+ info = session.TreeInfo()
+ root = self.AddRoot(info[0], -1, -1, None)
+ self.SetItemImage(root, self.emptyImageIndex)
+ self.add_items(root, info[1])
+ self.Expand(root)
+ # select the selected layer
+ selected_layer = self.mainwindow.current_layer()
+ if selected_layer is not None:
+ # One would expect that the selected_layer's id is in
+ # layer_to_item at this point as we've just rebuilt that
+ # mapping completely. However, when a new session is loaded
+ # for instance, it can happen that the tree view is updated
+ # before the canvas's selection in which case selected_layer
+ # may be a layer of the old session.
+ item = self.layer_to_item.get(id(selected_layer))
+ if item is not None:
+ self.SelectItem(item)
+
+ def add_items(self, parent, items):
+
+ if items is None: return
+
+ for item in items:
+ if hasattr(item, "TreeInfo"):
+ # Supports the TreeInfo protocol
+ info = item.TreeInfo()
+ treeitem = self.AppendItem(parent, info[0], -1, -1, None)
+ self.SetItemImage(treeitem, self.emptyImageIndex)
+ self.SetPyData(treeitem, item)
+ self.add_items(treeitem, info[1])
+ self.Expand(treeitem)
+ if isinstance(item, Layer):
+ self.layer_to_item[id(item)] = treeitem
+ elif isinstance(item, StringType) or \
+ isinstance(item, UnicodeType):
+ # it's a string
+ treeitem = self.AppendItem(parent, item, -1, -1, None)
+ self.SetItemImage(treeitem, self.emptyImageIndex)
+ else:
+ # assume its a sequence (title, items)
+ if isinstance(item[1], Color):
+
+ treeitem = self.AppendItem(parent, "(%s)" % item[0])
+
+ bmp = wx.EmptyBitmap(BMP_SIZE, BMP_SIZE)
+ brush = wx.Brush(Color2wxColour(item[1]), wx.SOLID)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bmp)
+ dc.SetBrush(brush)
+ dc.Clear()
+ dc.DrawRoundedRectangle(0, 0,
+ bmp.GetWidth(), bmp.GetHeight(),
+ 4)
+ dc.SelectObject(wx.NullBitmap)
+
+ i = self.image_list.Add(bmp)
+ self.SetItemImage(treeitem, i)
+ else:
+ treeitem = self.AppendItem(parent, item[0], -1, -1, None)
+ self.SetItemImage(treeitem, self.emptyImageIndex)
+ self.add_items(treeitem, item[1])
+ self.Expand(treeitem)
+
+ def session_changed(self, *args):
+ new_session = self.app.session
+ # if the session has changed subscribe/unsubscribe
+ if self.session is not new_session:
+ if self.session is not None:
+ self.session.Unsubscribe(CHANGED, self.update_tree)
+ if new_session is not None:
+ new_session.Subscribe(CHANGED, self.update_tree)
+ self.session = new_session
+ self.update_tree()
+
+ def normalize_selection(self):
+ """Select the layer or map containing currently selected item"""
+ item = self.GetSelection()
+ while item.IsOk():
+ object = self.GetPyData(item)
+ if isinstance(object, Layer) or isinstance(object, Map):
+ break
+ item = self.GetItemParent(item)
+ else:
+ # No layer or map was found in the chain of parents, so
+ # there's nothing we can do.
+ return
+
+ self.changing_selection = 1
+ try:
+ self.SelectItem(item)
+ finally:
+ self.changing_selection = 0
+
+ def SelectedLayer(self):
+ """Return the layer object currently selected in the tree.
+ Return None if no layer is selected"""
+ layer = self.GetPyData(self.GetSelection())
+ if isinstance(layer, Layer):
+ return layer
+ return None
+
+ def OnSelChanged(self, event):
+ if self.changing_selection:
+ # we're changing the selection ourselves (probably through
+ # self.normalize_selection(). ignore the event.
+ return
+ self.normalize_selection()
+ # SelectedLayer returns None if no layer is selected. Since
+ # passing None to SelectLayer deselects the layer we can simply
+ # pass the result of SelectedLayer on in all cases
+ self.mainwindow.SelectLayer(self.SelectedLayer())
+
+ def layer_selected(self, layer):
+ item = self.layer_to_item.get(id(layer))
+ if item is not None and item != self.GetSelection():
+ self.SelectItem(item)
+
+
+class SessionTreeView(NonModalNonParentDialog):
+
+ """Non modal dialog showing the session as a tree"""
+
+ def __init__(self, parent, app, name):
+ NonModalNonParentDialog.__init__(self, parent, name, _("Session"))
+ self.tree = SessionTreeCtrl(self, -1, parent, app)
+
+ def OnClose(self, event):
+ NonModalNonParentDialog.OnClose(self, event)
+
+ # if there were a way to get notified when the tree control
+ # itself is destroyed we could use that to unsubscribe instead
+ # of doing it here. (EVT_WINDOW_DESTROY doesn't seem to sent at
+ # all)
+ self.tree.unsubscribe_all()
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/view.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/view.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/view.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,446 @@
+# opyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Frank Koormann <frank at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes for display of a map and interaction with it
+"""
+
+from __future__ import generators
+
+__version__ = "$Revision: 2718 $"
+# $Source$
+# $Id: view.py 2718 2007-01-05 23:43:49Z dpinte $
+
+import os.path
+import time
+import traceback
+
+import wx
+
+# Export related stuff
+if wx.Platform == '__WXMSW__':
+ from wx import MetaFileDC
+
+from Thuban import _
+
+from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \
+ LAYER_VISIBILITY_CHANGED
+
+from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer
+
+import labeldialog
+
+from viewport import ViewPort, PanTool, output_transform
+
+class CanvasPanTool(PanTool):
+
+ """The Canvas Pan Tool"""
+
+ def MouseMove(self, event):
+ if self.dragging:
+ PanTool.MouseMove(self, event)
+ sx, sy = self.start
+ x, y = self.current
+ width, height = self.view.GetSizeTuple()
+
+ bitmapdc = wx.MemoryDC()
+ bitmapdc.SelectObject(self.view.PreviewBitmap())
+
+ dc = self.view.drag_dc
+ dc.Blit(0, 0, width, height, bitmapdc, sx - x, sy - y)
+
+class MapPrintout(wx.Printout):
+
+ """
+ wxPrintout class for printing Thuban maps
+ """
+
+ def __init__(self, canvas, map, region, selected_layer, selected_shapes):
+ wx.Printout.__init__(self)
+ self.canvas = canvas
+ self.map = map
+ self.region = region
+ self.selected_layer = selected_layer
+ self.selected_shapes = selected_shapes
+
+ def GetPageInfo(self):
+ return (1, 1, 1, 1)
+
+ def HasPage(self, pagenum):
+ return pagenum == 1
+
+ def OnPrintPage(self, pagenum):
+ if pagenum == 1:
+ self.draw_on_dc(self.GetDC())
+
+ def draw_on_dc(self, dc):
+ width, height = self.GetPageSizePixels()
+ scale, offset, mapregion = output_transform(self.canvas.scale,
+ self.canvas.offset,
+ self.canvas.GetSizeTuple(),
+ self.GetPageSizePixels())
+ resx, resy = self.GetPPIPrinter()
+ canvas_scale = self.canvas.scale
+ x, y, width, height = self.region
+ renderer = PrinterRenderer(dc, self.map, scale, offset,
+ region = (mapregion[0], mapregion[1],
+ (width/canvas_scale)*scale,
+ (height/canvas_scale)*scale),
+ resolution = resy,
+ destination_region = mapregion)
+ renderer.RenderMap(self.selected_layer, self.selected_shapes)
+ return True
+
+
+class MapCanvas(wx.Window, ViewPort):
+
+ """A widget that displays a map and offers some interaction"""
+
+ def __init__(self, parent, winid):
+ wx.Window.__init__(self, parent, winid)
+ ViewPort.__init__(self)
+
+ self.SetBackgroundColour(wx.Colour(255, 255, 255))
+
+ # the bitmap serving as backing store
+ self.bitmap = None
+ # the monochrome bitmap with the selection if any
+ self.selection_bitmap = None
+
+ self.backgroundColor = wx.WHITE_BRUSH
+
+ # The rendering iterator object. Used when rendering
+ # incrementally
+ self.render_iter = None
+
+ # subscribe the WX events we're interested in
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+ self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+ self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
+ self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
+ self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
+ self.Bind(wx.EVT_MOTION, self.OnMotion)
+ self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
+ self.Bind(wx.EVT_SIZE, self.OnSize)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+ def __del__(self):
+ wx.Window.__del__(self)
+ ViewPort.__del__(self)
+
+ def PreviewBitmap(self):
+ return self.bitmap
+
+ def PanTool(self):
+ """Start the canvas pan tool"""
+ self.SelectTool(CanvasPanTool(self))
+
+ def SetMap(self, map):
+ redraw_channels = (MAP_LAYERS_CHANGED, LAYER_CHANGED,
+ LAYER_VISIBILITY_CHANGED)
+ if self.Map() is not None:
+ for channel in redraw_channels:
+ self.Map().Unsubscribe(channel, self.full_redraw)
+
+ ViewPort.SetMap(self, map)
+
+ if self.Map() is not None:
+ for channel in redraw_channels:
+ self.Map().Subscribe(channel, self.full_redraw)
+
+ # force a redraw. If map is not empty, it's already been called
+ # by FitMapToWindow but if map is empty it hasn't been called
+ # yet so we have to explicitly call it.
+ self.full_redraw()
+
+ def OnPaint(self, event):
+ dc = wx.PaintDC(self)
+ if self.Map() is not None and self.Map().HasLayers():
+ if self.bitmap is not None:
+ dc.BeginDrawing()
+ dc.DrawBitmap(self.bitmap, 0, 0)
+ if self.selection_bitmap is not None:
+ dc.DrawBitmap(self.selection_bitmap, 0, 0, True)
+ dc.EndDrawing()
+ else:
+ # If we've got no map or if the map is empty, simply clear
+ # the screen.
+
+ # XXX it's probably possible to get rid of this. The
+ # background color of the window is already white and the
+ # only thing we may have to do is to call self.Refresh()
+ # with a true argument in the right places.
+ dc.BeginDrawing()
+ dc.SetBackground(self.backgroundColor)
+ dc.Clear()
+ dc.EndDrawing()
+
+ def OnIdle(self, event):
+ """Idle handler. Redraw the bitmap if necessary"""
+ if (self.Map() is not None
+ and (self.bitmap is None
+ or self.render_iter is not None
+ or (self.HasSelectedShapes()
+ and self.selection_bitmap is None))):
+ event.RequestMore(self._do_redraw())
+
+ def _do_redraw(self):
+ """Redraw a bit and return whether this method has to be called again.
+
+ Called by OnIdle to handle the actual redraw. Redraw is
+ incremental for both the bitmap with the normal layers and the
+ bitmap with the selection.
+ """
+ finished = False
+ if self.render_iter is not None:
+ try:
+ if self.render_iter.next():
+ # Redraw if the last preview redraw was some time
+ # ago and the user is not currently dragging the
+ # mouse because redrawing would interfere with what
+ # the current tool is drawing on the window.
+ if not self.dragging \
+ and time.time() - self.render_last_preview > 0.5:
+ client_dc = wx.ClientDC(self)
+ client_dc.BeginDrawing()
+ client_dc.DrawBitmap(self.bitmap, 0, 0)
+ client_dc.EndDrawing()
+ self.render_last_preview = time.time()
+ else:
+ self.render_iter = None
+ # Redraw if not dragging because redrawing would
+ # interfere with what the current tool is drawing on
+ # the window.
+ if not self.dragging:
+ self.redraw()
+ finished = True
+ except StopIteration:
+ finished = True
+ self.render_iter = None
+ except:
+ finished = True
+ self.render_iter = None
+ traceback.print_exc()
+ else:
+ self.render_iter = self._render_iterator()
+ self.render_last_preview = time.time()
+ return not finished
+
+ def _render_iterator(self):
+ width, height = self.GetSizeTuple()
+ dc = wx.MemoryDC()
+
+ render_start = time.time()
+
+ if self.bitmap is None:
+ self.bitmap = wx.EmptyBitmap(width, height)
+ dc.SelectObject(self.bitmap)
+ dc.BeginDrawing()
+
+ dc.SetBackground(self.backgroundColor)
+ dc.Clear()
+
+ # draw the map into the bitmap
+ renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
+ (0, 0, width, height))
+ for cont in renderer.RenderMapIncrementally():
+ yield True
+
+ dc.EndDrawing()
+ dc.SelectObject(wx.NullBitmap)
+
+ if self.HasSelectedShapes() and self.selection_bitmap is None:
+ bitmap = wx.EmptyBitmap(width, height)
+ dc.SelectObject(bitmap)
+ dc.BeginDrawing()
+ dc.SetBackground(wx.WHITE_BRUSH)
+ dc.Clear()
+
+ renderer = ScreenRenderer(dc, self.Map(), self.scale, self.offset,
+ (0, 0, width, height))
+ layer = self.SelectedLayer()
+ shapes = self.selection.SelectedShapes()
+ for cont in renderer.draw_selection_incrementally(layer, shapes):
+ yield True
+
+ dc.EndDrawing()
+ dc.SelectObject(wx.NullBitmap)
+
+ bitmap.SetMask(wx.Mask(bitmap, wx.WHITE))
+ self.selection_bitmap = bitmap
+
+ yield False
+
+ def Export(self):
+
+ if hasattr(self, "export_path"):
+ export_path = self.export_path
+ else:
+ export_path="."
+ dlg = wx.FileDialog(self, _("Export Map"), export_path, "",
+ "Enhanced Metafile (*.wmf)|*.wmf",
+ wx.SAVE|wx.OVERWRITE_PROMPT)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.export_path = os.path.dirname(dlg.GetPath())
+ dc = wx.MetaFileDC(dlg.GetPath())
+
+ scale, offset, mapregion = output_transform(self.scale,
+ self.offset,
+ self.GetSizeTuple(),
+ dc.GetSizeTuple())
+
+ selected_layer = self.selection.SelectedLayer()
+ selected_shapes = self.selection.SelectedShapes()
+
+ width, height = self.GetSizeTuple()
+ renderer = ExportRenderer(dc, self.Map(), scale, offset,
+ region = (0, 0,
+ (width/self.scale)*scale,
+ (height/self.scale)*scale),
+ destination_region = mapregion)
+ renderer.RenderMap(selected_layer, selected_shapes)
+
+ dc.EndDrawing()
+ dc.Close()
+ dlg.Destroy()
+
+ def Print(self):
+ printer = wx.Printer()
+ width, height = self.GetSizeTuple()
+ selected_layer = self.selection.SelectedLayer()
+ selected_shapes = self.selection.SelectedShapes()
+
+ printout = MapPrintout(self, self.Map(), (0, 0, width, height),
+ selected_layer, selected_shapes)
+ printer.Print(self, printout, True)
+ printout.Destroy()
+
+ def redraw(self, *args):
+ self.Refresh(False)
+
+ def full_redraw(self, *args):
+ self.bitmap = None
+ self.selection_bitmap = None
+ self.render_iter = None
+ self.redraw()
+
+ def redraw_selection(self, *args):
+ self.selection_bitmap = None
+ self.render_iter = None
+ self.redraw()
+
+ def map_projection_changed(self, map, old_proj):
+ ViewPort.map_projection_changed(self, map, old_proj)
+ self.full_redraw()
+
+ def layer_projection_changed(self, *args):
+ ViewPort.layer_projection_changed(self, args)
+ self.full_redraw()
+
+ def set_view_transform(self, scale, offset):
+ ViewPort.set_view_transform(self, scale, offset)
+ self.full_redraw()
+
+ def GetPortSizeTuple(self):
+ return self.GetSizeTuple()
+
+ def OnMiddleDown(self, event):
+ self.remembertool = self.tool
+ if self.Map() is not None and self.Map().HasLayers():
+ self.PanTool()
+ self.OnLeftDown(event)
+
+ def OnMiddleUp(self, event):
+ self.OnLeftUp(event)
+ if self.remembertool:
+ self.SelectTool(self.remembertool)
+
+ def OnLeftDown(self, event):
+ self.MouseLeftDown(event)
+ if self.tool is not None:
+ self.drag_dc = wx.ClientDC(self)
+ self.drag_dc.SetLogicalFunction(wx.INVERT)
+ self.drag_dc.SetBrush(wx.TRANSPARENT_BRUSH)
+ self.tool.Show(self.drag_dc)
+ self.CaptureMouse()
+ self.dragging = 1
+
+ def OnLeftUp(self, event):
+ """Handle EVT_LEFT_UP
+
+ Release the mouse if it was captured, if a tool is active call
+ its Hide method and call self.MouseLeftUp.
+ """
+ # It's important that ReleaseMouse is called before MouseLeftUp.
+ # MouseLeftUp may pop up modal dialogs which leads to an
+ # effectively frozen X session because the user can only
+ # interact with the dialog but the mouse is still grabbed by the
+ # canvas.
+ if self.dragging:
+ if self.HasCapture():
+ self.ReleaseMouse()
+ try:
+ self.tool.Hide(self.drag_dc)
+ finally:
+ self.drag_dc = None
+ self.dragging = 0
+ self.MouseLeftUp(event)
+
+ def OnMotion(self, event):
+ if self.dragging:
+ self.tool.Hide(self.drag_dc)
+
+ self.MouseMove(event)
+
+ if self.dragging:
+ self.tool.Show(self.drag_dc)
+
+ def OnLeaveWindow(self, event):
+ self.set_current_position(None)
+
+ def OnSize(self, event):
+ # the window's size has changed. We have to get a new bitmap. If
+ # we want to be clever we could try to get by without throwing
+ # everything away. E.g. when the window gets smaller, we could
+ # either keep the bitmap or create the new one from the old one.
+ # Even when the window becomes larger some parts of the bitmap
+ # could be reused.
+ self.full_redraw()
+
+ def shape_selected(self, layer, shape):
+ """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
+ # The selection object takes care that it only issues
+ # SHAPES_SELECTED messages when the set of selected shapes has
+ # actually changed, so we can do a full redraw of the
+ # selection_bitmap unconditionally.
+ ViewPort.shape_selected(self, layer, shape)
+ self.redraw_selection()
+
+ def GetTextExtent(self, text):
+ dc = wx.ClientDC(self)
+ font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
+ dc.SetFont(font)
+ return dc.GetTextExtent(text.decode('iso-8859-1'))
+
+ def LabelShapeAt(self, x, y, text=None):
+ """Add or remove a label at window position x, y.
+
+ If there's a label at the given position, remove it. Otherwise
+ determine the shape at the position, run the label dialog and
+ unless the user cancels the dialog, add a label.
+ """
+ layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
+ if layer is None and shape_index is not None:
+ ViewPort.LabelShapeAt(self, x, y)
+ elif layer is not None:
+ text = labeldialog.run_label_dialog(self,
+ layer.ShapeStore().Table(),
+ shape_index)
+ ViewPort.LabelShapeAt(self, x, y, text)
+
+
Added: packages/thuban/branches/upstream/current/Thuban/UI/viewport.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/UI/viewport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/UI/viewport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1006 @@
+# Copyright (c) 2003-2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de> (2003, 2004)
+# Jonathan Coles <jonathan at intevation.de> (2003)
+# Jan-Oliver Wagner <jan at intevation.de> (2004)
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Classes for display of a map and interaction with it
+"""
+
+__version__ = "$Revision: 2710 $"
+# $Source$
+# $Id: viewport.py 2710 2006-10-10 08:31:44Z dpinte $
+
+import sys
+from math import hypot
+
+from wxproj import point_in_polygon_shape, shape_centroid
+
+from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \
+ LAYER_PROJECTION_CHANGED, TITLE_CHANGED, \
+ MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
+ SHAPETYPE_POINT, RAW_SHAPEFILE
+from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
+ ALIGN_LEFT, ALIGN_RIGHT
+from Thuban.Lib.connector import Publisher, Conduit
+from Thuban.Model.color import Transparent
+
+from selection import Selection
+
+from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \
+ SCALE_CHANGED, MAP_REPLACED
+
+import hittest
+
+#
+# The tools
+#
+
+class Tool:
+
+ """
+ Base class for the interactive tools
+ """
+
+ def __init__(self, view):
+ """Intitialize the tool. The view is the canvas displaying the map"""
+ self.view = view
+ self.start = self.current = None
+ self.dragging = 0
+ self.drawn = 0
+
+ def __del__(self):
+ del self.view
+
+ def Name(self):
+ """Return the tool's name"""
+ return ''
+
+ def drag_start(self, x, y):
+ self.start = self.current = x, y
+ self.dragging = 1
+
+ def drag_move(self, x, y):
+ self.current = x, y
+
+ def drag_stop(self, x, y):
+ self.current = x, y
+ self.dragging = 0
+
+ def Show(self, dc):
+ if not self.drawn:
+ self.draw(dc)
+ self.drawn = 1
+
+ def Hide(self, dc):
+ if self.drawn:
+ self.draw(dc)
+ self.drawn = 0
+
+ def draw(self, dc):
+ pass
+
+ def MouseDown(self, event):
+ self.drag_start(event.m_x, event.m_y)
+
+ def MouseMove(self, event):
+ if self.dragging:
+ self.drag_move(event.m_x, event.m_y)
+
+ def MouseUp(self, event):
+ if self.dragging:
+ self.drag_stop(event.m_x, event.m_y)
+
+ def Cancel(self):
+ self.dragging = 0
+
+
+class RectTool(Tool):
+
+ """Base class for tools that draw rectangles while dragging"""
+
+ def draw(self, dc):
+ sx, sy = self.start
+ cx, cy = self.current
+ dc.DrawRectangle(sx, sy, cx - sx, cy - sy)
+
+class ZoomInTool(RectTool):
+
+ """The Zoom-In Tool"""
+
+ def Name(self):
+ return "ZoomInTool"
+
+ def proj_rect(self):
+ """return the rectangle given by start and current in projected
+ coordinates"""
+ sx, sy = self.start
+ cx, cy = self.current
+ left, top = self.view.win_to_proj(sx, sy)
+ right, bottom = self.view.win_to_proj(cx, cy)
+ return (min(left, right), min(top, bottom),
+ max(left, right), max(top, bottom))
+
+ def MouseUp(self, event):
+ if self.dragging:
+ Tool.MouseUp(self, event)
+ sx, sy = self.start
+ cx, cy = self.current
+ if sx == cx or sy == cy:
+ # Just a mouse click or a degenerate rectangle. Simply
+ # zoom in by a factor of two
+ # FIXME: For a click this is the desired behavior but should we
+ # really do this for degenrate rectagles as well or
+ # should we ignore them?
+ self.view.ZoomFactor(2, center = (cx, cy))
+ else:
+ # A drag. Zoom in to the rectangle
+ self.view.FitRectToWindow(self.proj_rect())
+
+
+class ZoomOutTool(RectTool):
+
+ """The Zoom-Out Tool"""
+
+ def Name(self):
+ return "ZoomOutTool"
+
+ def MouseUp(self, event):
+ if self.dragging:
+ Tool.MouseUp(self, event)
+ sx, sy = self.start
+ cx, cy = self.current
+ if sx == cx or sy == cy:
+ # Just a mouse click or a degenerate rectangle. Simply
+ # zoom out by a factor of two.
+ # FIXME: For a click this is the desired behavior but should we
+ # really do this for degenrate rectagles as well or
+ # should we ignore them?
+ self.view.ZoomFactor(0.5, center = (cx, cy))
+ else:
+ # A drag. Zoom out to the rectangle
+ self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
+ max(sx, cx), max(sy, cy)))
+
+class PanTool(Tool):
+
+ """The Pan Tool"""
+
+ def Name(self):
+ return "PanTool"
+
+ def MouseMove(self, event):
+ if self.dragging:
+ Tool.MouseMove(self, event)
+
+ def MouseUp(self, event):
+ if self.dragging:
+ Tool.MouseUp(self, event)
+ sx, sy = self.start
+ cx, cy = self.current
+ self.view.Translate(cx - sx, cy - sy)
+
+class IdentifyTool(Tool):
+
+ """The "Identify" Tool"""
+
+ def Name(self):
+ return "IdentifyTool"
+
+ def MouseUp(self, event):
+ self.view.SelectShapeAt(event.m_x, event.m_y)
+
+
+class LabelTool(Tool):
+
+ """The "Label" Tool"""
+
+ def Name(self):
+ return "LabelTool"
+
+ def MouseUp(self, event):
+ self.view.LabelShapeAt(event.m_x, event.m_y)
+
+
+class ViewPort(Conduit):
+
+ """An abstract view of the main window"""
+
+ # Some messages that can be subscribed/unsubscribed directly through
+ # the MapCanvas come in fact from other objects. This is a dict
+ # mapping those messages to the names of the instance variables they
+ # actually come from. The delegation is implemented in the Subscribe
+ # and Unsubscribe methods
+ delegated_messages = {LAYER_SELECTED: "selection",
+ SHAPES_SELECTED: "selection"}
+
+ # Methods delegated to some instance variables. The delegation is
+ # implemented in the __getattr__ method.
+ delegated_methods = {"SelectLayer": "selection",
+ "SelectShapes": "selection",
+ "SelectedLayer": "selection",
+ "HasSelectedLayer": "selection",
+ "HasSelectedShapes": "selection",
+ "SelectedShapes": "selection"}
+
+ # Some messages are forwarded from the currently shown map. This is
+ # simply a list of the channels to forward. The _subscribe_map and
+ # _unsubscribe_map methods use this to handle the forwarding.
+ forwarded_map_messages = (LAYER_PROJECTION_CHANGED, TITLE_CHANGED,
+ MAP_PROJECTION_CHANGED,
+ MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED)
+
+ def __init__(self, size = (400, 300)):
+
+ self.size = size
+
+ # the map displayed in this canvas. Set with SetMap()
+ self.map = None
+
+ # scale and offset describe the transformation from projected
+ # coordinates to window coordinates.
+ self.scale = 1.0
+ self.offset = (0, 0)
+
+ # whether the user is currently dragging the mouse, i.e. moving
+ # the mouse while pressing a mouse button
+ self.dragging = 0
+
+ # the currently active tool
+ self.tool = None
+
+ # The current mouse position of the last OnMotion event or None
+ # if the mouse is outside the window.
+ self.current_position = None
+
+ # the selection
+ self.selection = Selection()
+ self.selection.Subscribe(SHAPES_SELECTED, self.shape_selected)
+
+ # keep track of which layers/shapes are selected to make sure we
+ # only redraw when necessary
+ self.last_selected_layer = None
+ self.last_selected_shape = None
+
+ def Destroy(self):
+ self._unsubscribe_map(self.map)
+ self.map = None
+ self.selection.Destroy()
+ self.tool = None
+
+ def Subscribe(self, channel, *args):
+ """Extend the inherited method to handle delegated messages.
+
+ If channel is one of the delegated messages call the appropriate
+ object's Subscribe method. Otherwise just call the inherited
+ method.
+ """
+ if channel in self.delegated_messages:
+ object = getattr(self, self.delegated_messages[channel])
+ object.Subscribe(channel, *args)
+ else:
+ Conduit.Subscribe(self, channel, *args)
+
+ def Unsubscribe(self, channel, *args):
+ """Extend the inherited method to handle delegated messages.
+
+ If channel is one of the delegated messages call the appropriate
+ object's Unsubscribe method. Otherwise just call the inherited
+ method.
+ """
+ if channel in self.delegated_messages:
+ object = getattr(self, self.delegated_messages[channel])
+ object.Unsubscribe(channel, *args)
+ else:
+ Conduit.Unsubscribe(self, channel, *args)
+
+ def __getattr__(self, attr):
+ if attr in self.delegated_methods:
+ return getattr(getattr(self, self.delegated_methods[attr]), attr)
+ raise AttributeError(attr)
+
+ def SetMap(self, map):
+ self._unsubscribe_map(self.map)
+ changed = self.map is not map
+ self.map = map
+ self.selection.ClearSelection()
+ self._subscribe_map(self.map)
+ self.FitMapToWindow()
+ self.issue(MAP_REPLACED)
+
+ def _subscribe_map(self, map):
+ """Internal: Subscribe to some of the map's messages"""
+ if map is not None:
+ map.Subscribe(LAYER_PROJECTION_CHANGED,
+ self.layer_projection_changed)
+ map.Subscribe(MAP_PROJECTION_CHANGED,
+ self.map_projection_changed)
+ for channel in self.forwarded_map_messages:
+ self.subscribe_forwarding(channel, map)
+
+ def _unsubscribe_map(self, map):
+ """
+ Internal: Unsubscribe from the messages subscribed to in _subscribe_map
+ """
+ if map is not None:
+ for channel in self.forwarded_map_messages:
+ self.unsubscribe_forwarding(channel, map)
+ map.Unsubscribe(MAP_PROJECTION_CHANGED,
+ self.map_projection_changed)
+ map.Unsubscribe(LAYER_PROJECTION_CHANGED,
+ self.layer_projection_changed)
+
+ def Map(self):
+ """Return the map displayed by this canvas or None if no map is shown
+ """
+ return self.map
+
+ def map_projection_changed(self, map, old_proj):
+ """Subscribed to the map's MAP_PROJECTION_CHANGED message
+
+ If the projection changes, the region shown is probably not
+ meaningful anymore in the new projection. Therefore this method
+ tries to keep the same region visible as before.
+ """
+ proj = self.map.GetProjection()
+
+ bbox = None
+
+ if old_proj is not None and proj is not None and self.map.HasLayers():
+ width, height = self.GetPortSizeTuple()
+ llx, lly = self.win_to_proj(0, height)
+ urx, ury = self.win_to_proj(width, 0)
+ bbox = old_proj.InverseBBox((llx, lly, urx, ury))
+ bbox = proj.ForwardBBox(bbox)
+
+ if bbox is not None:
+ self.FitRectToWindow(bbox)
+ else:
+ self.FitMapToWindow()
+
+ def layer_projection_changed(self, *args):
+ """Subscribed to the LAYER_PROJECTION_CHANGED messages
+
+ This base-class implementation does nothing currently, but it
+ can be extended in derived classes to e.g. redraw the window.
+ """
+
+ def calc_min_max_scales(self, scale = None):
+ if scale is None:
+ scale = self.scale
+
+ llx, lly, urx, ury = bbox = self.map.ProjectedBoundingBox()
+ pwidth = float(urx - llx)
+ pheight = float(ury - lly)
+
+ # width/height of the window
+ wwidth, wheight = self.GetPortSizeTuple()
+
+ # The window coordinates used when drawing the shapes must fit
+ # into 16bit signed integers.
+ max_len = max(pwidth, pheight)
+ if max_len:
+ max_scale = 32767.0 / max_len
+ else:
+ # FIXME: What to do in this case? The bbox is effectively
+ # empty so any scale should work.
+ max_scale = scale
+
+ # The minimal scale is somewhat arbitrarily set to half that of
+ # the bbox fit into the window
+ scales = []
+ if pwidth:
+ scales.append(wwidth / pwidth)
+ if pheight:
+ scales.append(wheight / pheight)
+ if scales:
+ min_scale = 0.5 * min(scales)
+ else:
+ min_scale = scale
+
+ return min_scale, max_scale
+
+ def set_view_transform(self, scale, offset):
+ # width/height of the window
+ wwidth, wheight = self.GetPortSizeTuple()
+
+ # The window's center in projected coordinates assuming the new
+ # scale/offset
+ try:
+ pcenterx = (wwidth/2 - offset[0]) / scale
+ pcentery = (offset[1] - wheight/2) / scale
+ except ZeroDivisionError:
+ # scale was zero. Probably a problem with the projections.
+ # printing an error message and return immediately. The user
+ # will hopefully be informed by the UI which displays a
+ # message for at least some of the projection problems.
+ print >>sys.stderr, "ViewPort.set_view_transform:", \
+ "ZeroDivisionError, scale =", repr(scale)
+ return
+
+ min_scale, max_scale = self.calc_min_max_scales(scale)
+
+ if scale > max_scale:
+ scale = max_scale
+ elif scale < min_scale:
+ scale = min_scale
+
+ self.scale = scale
+
+ # determine new offset to preserve the center
+ self.offset = (wwidth/2 - scale * pcenterx,
+ wheight/2 + scale * pcentery)
+ self.issue(SCALE_CHANGED, scale)
+
+ def GetPortSizeTuple(self):
+ return self.size
+
+ def proj_to_win(self, x, y):
+ """\
+ Return the point in window coords given by projected coordinates x y
+ """
+ offx, offy = self.offset
+ return (self.scale * x + offx, -self.scale * y + offy)
+
+ def win_to_proj(self, x, y):
+ """\
+ Return the point in projected coordinates given by window coords x y
+ """
+ offx, offy = self.offset
+ return ((x - offx) / self.scale, (offy - y) / self.scale)
+
+ def VisibleExtent(self):
+ """Return the extent of the visible region in projected coordinates
+
+ The return values is a tuple (llx, lly, urx, ury) describing the
+ region.
+ """
+ width, height = self.GetPortSizeTuple()
+ llx, lly = self.win_to_proj(0, height)
+ urx, ury = self.win_to_proj(width, 0)
+ return (llx, lly, urx, ury)
+
+ def FitRectToWindow(self, rect):
+ """Fit the rectangular region given by rect into the window.
+
+ Set scale so that rect (in projected coordinates) just fits into
+ the window and center it.
+ """
+ width, height = self.GetPortSizeTuple()
+ llx, lly, urx, ury = rect
+ if llx == urx or lly == ury:
+ # zero width or zero height. Do Nothing
+ return
+ scalex = width / (urx - llx)
+ scaley = height / (ury - lly)
+ scale = min(scalex, scaley)
+ offx = 0.5 * (width - (urx + llx) * scale)
+ offy = 0.5 * (height + (ury + lly) * scale)
+ self.set_view_transform(scale, (offx, offy))
+
+ def FitMapToWindow(self):
+ """Fit the map to the window
+
+ Set the scale so that the map fits exactly into the window and
+ center it in the window.
+ """
+ if self.map is not None:
+ bbox = self.map.ProjectedBoundingBox()
+ if bbox is not None:
+ self.FitRectToWindow(bbox)
+
+ def FitLayerToWindow(self, layer):
+ """Fit the given layer to the window.
+
+ Set the scale so that the layer fits exactly into the window and
+ center it in the window.
+ """
+
+ bbox = layer.LatLongBoundingBox()
+ if bbox is not None:
+ proj = self.map.GetProjection()
+ if proj is not None:
+ bbox = proj.ForwardBBox(bbox)
+
+ if bbox is not None:
+ self.FitRectToWindow(bbox)
+
+ def FitSelectedToWindow(self):
+ layer = self.selection.SelectedLayer()
+ shapes = self.selection.SelectedShapes()
+
+ bbox = layer.ShapesBoundingBox(shapes)
+ if bbox is not None:
+ proj = self.map.GetProjection()
+ if proj is not None:
+ bbox = proj.ForwardBBox(bbox)
+
+ if bbox is not None:
+ if len(shapes) == 1 and layer.ShapeType() == SHAPETYPE_POINT:
+ self.ZoomFactor(self.calc_min_max_scales()[1] / self.scale,
+ self.proj_to_win(bbox[0], bbox[1]))
+ else:
+ self.FitRectToWindow(bbox)
+
+ def ZoomFactor(self, factor, center = None):
+ """Multiply the zoom by factor and center on center.
+
+ The optional parameter center is a point in window coordinates
+ that should be centered. If it is omitted, it defaults to the
+ center of the window
+ """
+ width, height = self.GetPortSizeTuple()
+ scale = self.scale * factor
+ offx, offy = self.offset
+ if center is not None:
+ cx, cy = center
+ else:
+ cx = width / 2
+ cy = height / 2
+ offset = (factor * (offx - cx) + width / 2,
+ factor * (offy - cy) + height / 2)
+ self.set_view_transform(scale, offset)
+
+ def ZoomOutToRect(self, rect):
+ """Zoom out to fit the currently visible region into rect.
+
+ The rect parameter is given in window coordinates
+ """
+ # determine the bbox of the displayed region in projected
+ # coordinates
+ width, height = self.GetPortSizeTuple()
+ llx, lly = self.win_to_proj(0, height - 1)
+ urx, ury = self.win_to_proj(width - 1, 0)
+
+ sx, sy, ex, ey = rect
+ scalex = (ex - sx) / (urx - llx)
+ scaley = (ey - sy) / (ury - lly)
+ scale = min(scalex, scaley)
+
+ offx = 0.5 * ((ex + sx) - (urx + llx) * scale)
+ offy = 0.5 * ((ey + sy) + (ury + lly) * scale)
+ self.set_view_transform(scale, (offx, offy))
+
+ def Translate(self, dx, dy):
+ """Move the map by dx, dy pixels"""
+ offx, offy = self.offset
+ self.set_view_transform(self.scale, (offx + dx, offy + dy))
+
+ def SelectTool(self, tool):
+ """Make tool the active tool.
+
+ The parameter should be an instance of Tool or None to indicate
+ that no tool is active.
+ """
+ self.tool = tool
+
+ def ZoomInTool(self):
+ """Start the zoom in tool"""
+ self.SelectTool(ZoomInTool(self))
+
+ def ZoomOutTool(self):
+ """Start the zoom out tool"""
+ self.SelectTool(ZoomOutTool(self))
+
+ def PanTool(self):
+ """Start the pan tool"""
+ self.SelectTool(PanTool(self))
+
+ def IdentifyTool(self):
+ """Start the identify tool"""
+ self.SelectTool(IdentifyTool(self))
+
+ def LabelTool(self):
+ """Start the label tool"""
+ self.SelectTool(LabelTool(self))
+
+ def CurrentTool(self):
+ """Return the name of the current tool or None if no tool is active"""
+ return self.tool and self.tool.Name() or None
+
+ def CurrentPosition(self):
+ """Return current position of the mouse in projected coordinates.
+
+ The result is a 2-tuple of floats with the coordinates. If the
+ mouse is not in the window, the result is None.
+ """
+ if self.current_position is not None:
+ x, y = self.current_position
+ return self.win_to_proj(x, y)
+ else:
+ return None
+
+ def set_current_position(self, event):
+ """Set the current position from event
+
+ Should be called by all events that contain mouse positions
+ especially EVT_MOTION. The event parameter may be None to
+ indicate the the pointer left the window.
+ """
+ if event is not None:
+ self.current_position = (event.m_x, event.m_y)
+ else:
+ self.current_position = None
+ self.issue(VIEW_POSITION)
+
+ def MouseLeftDown(self, event):
+ self.set_current_position(event)
+ if self.tool is not None:
+ self.tool.MouseDown(event)
+
+ def MouseLeftUp(self, event):
+ self.set_current_position(event)
+ if self.tool is not None:
+ self.tool.MouseUp(event)
+
+ def MouseMove(self, event):
+ self.set_current_position(event)
+ if self.tool is not None:
+ self.tool.MouseMove(event)
+
+ def shape_selected(self, layer, shape):
+ """Receiver for the SHAPES_SELECTED messages. Redraw the map."""
+ # The selection object takes care that it only issues
+ # SHAPES_SELECTED messages when the set of selected shapes has
+ # actually changed, so we can do a full redraw unconditionally.
+ # FIXME: We should perhaps try to limit the redraw to the are
+ # actually covered by the shapes before and after the selection
+ # change.
+ pass
+
+ def unprojected_rect_around_point(self, x, y, dist):
+ """Return a rect dist pixels around (x, y) in unprojected coordinates
+
+ The return value is a tuple (minx, miny, maxx, maxy) suitable a
+ parameter to a layer's ShapesInRegion method.
+ """
+ map_proj = self.map.projection
+ if map_proj is not None:
+ inverse = map_proj.Inverse
+ else:
+ inverse = None
+
+ xs = []
+ ys = []
+ for dx, dy in ((-1, -1), (1, -1), (1, 1), (-1, 1)):
+ px, py = self.win_to_proj(x + dist * dx, y + dist * dy)
+ if inverse:
+ px, py = inverse(px, py)
+ xs.append(px)
+ ys.append(py)
+ return (min(xs), min(ys), max(xs), max(ys))
+
+ def GetTextExtent(self, text):
+ """Return the extent of the text
+
+ This method must be implemented by derived classes. The return
+ value must have the same format as that of the GetTextExtent of
+ the wx DC objects.
+ """
+ raise NotImplementedError
+
+ def find_shape_at(self, px, py, select_labels = 0, searched_layer = None):
+ """Determine the shape at point px, py in window coords
+
+ Return the shape and the corresponding layer as a tuple (layer,
+ shapeid).
+
+ If the optional parameter select_labels is true (default false)
+ search through the labels. If a label is found return it's index
+ as the shape and None as the layer.
+
+ If the optional parameter searched_layer is given (or not None
+ which it defaults to), only search in that layer.
+ """
+
+ # First if the caller wants to select labels, search and return
+ # it if one is found. We must do this first because the labels
+ # are currently always drawn above all other layers.
+ if select_labels:
+ label = self._find_label_at(px, py)
+ if label is not None:
+ return None, label
+
+ #
+ # Search the normal layers
+ #
+
+ # Determine which layers to search. If the caller gave a
+ # specific layer, we only search that. Otherwise we have to
+ # search all visible vector layers in the map in reverse order.
+ if searched_layer:
+ layers = [searched_layer]
+ else:
+ layers = [layer for layer in self.map.Layers()
+ if layer.HasShapes() and layer.Visible()]
+ layers.reverse()
+
+ # Search through the layers.
+ for layer in layers:
+ shape = self._find_shape_in_layer(layer, px, py)
+ if shape is not None:
+ return layer, shape
+ return None, None
+
+ def _find_shape_in_layer(self, layer, px, py):
+ """Internal: Return the id of the shape at (px, py) in layer
+
+ Return None if no shape is at those coordinates.
+ """
+
+ # For convenience, bind some methods and values to local
+ # variables.
+ map_proj = self.map.projection
+ if map_proj is not None:
+ forward = map_proj.Forward
+ else:
+ forward = None
+
+ scale = self.scale
+
+ offx, offy = self.offset
+
+ table = layer.ShapeStore().Table()
+ lc = layer.GetClassification()
+ field = layer.GetClassificationColumn()
+
+ # defaults to fall back on
+ filled = lc.GetDefaultFill() is not Transparent
+ stroked = lc.GetDefaultLineColor() is not Transparent
+
+ # Determine the ids of the shapes that overlap a tiny area
+ # around the point. For layers containing points we have to
+ # choose a larger size of the box we're testing against so
+ # that we take the size of the markers into account
+ # The size of the box is determined by the largest symbol
+ # of the corresponding layer.
+ maxsize = 1
+ if layer.ShapeType() == SHAPETYPE_POINT:
+ for group in layer.GetClassification():
+ props = group.GetProperties()
+ if props.GetSize() > maxsize:
+ maxsize = props.GetSize()
+ box = self.unprojected_rect_around_point(px, py, maxsize)
+
+ # determine the function that does the hit test based on the layer
+ hittester = self._get_hit_tester(layer)
+
+ for shape in layer.ShapesInRegion(box):
+ if field:
+ record = table.ReadRowAsDict(shape.ShapeID())
+ group = lc.FindGroup(record[field])
+ props = group.GetProperties()
+ filled = props.GetFill() is not Transparent
+ stroked = props.GetLineColor() is not Transparent
+
+ if layer.ShapeType() == SHAPETYPE_POINT:
+ hit = hittester(layer, shape, filled, stroked,
+ px, py, size = props.GetSize())
+ else:
+ hit = hittester(layer, shape, filled, stroked, px, py)
+
+ if hit:
+ return shape.ShapeID()
+ return None
+
+ def _get_hit_tester(self, layer):
+ """Internal: Return a hit tester suitable for the layer
+
+ The return value is a callable that accepts a shape object and
+ some other parameters and and returns a boolean to indicate
+ whether that shape has been hit. The callable is called like
+ this:
+
+ callable(layer, shape, filled, stroked, x, y)
+ """
+ store = layer.ShapeStore()
+ shapetype = store.ShapeType()
+
+ if shapetype == SHAPETYPE_POINT:
+ return self._hit_point
+ elif shapetype == SHAPETYPE_ARC:
+ return self._hit_arc
+ elif shapetype == SHAPETYPE_POLYGON:
+ return self._hit_polygon
+ else:
+ raise ValueError("Unknown shapetype %r" % shapetype)
+
+ def projected_points(self, layer, points):
+ """Return the projected coordinates of the points taken from layer.
+
+ Transform all the points in the list of lists of coordinate
+ pairs in points.
+
+ The transformation applies the inverse of the layer's projection
+ if any, then the map's projection if any and finally applies
+ self.scale and self.offset.
+
+ The returned list has the same structure as the one returned the
+ shape's Points method.
+ """
+ proj = self.map.GetProjection()
+ if proj is not None:
+ forward = proj.Forward
+ else:
+ forward = None
+ proj = layer.GetProjection()
+ if proj is not None:
+ inverse = proj.Inverse
+ else:
+ inverse = None
+ result = []
+ scale = self.scale
+ offx, offy = self.offset
+ for part in points:
+ result.append([])
+ for x, y in part:
+ if inverse:
+ x, y = inverse(x, y)
+ if forward:
+ x, y = forward(x, y)
+ result[-1].append((x * scale + offx,
+ -y * scale + offy))
+ return result
+
+ def _hit_point(self, layer, shape, filled, stroked, px, py, size = 5):
+ """Internal: return whether a click at (px,py) hits the point shape
+
+ The filled and stroked parameters determine whether the shape is
+ assumed to be filled or stroked respectively.
+
+ size -- defines the size of the point symbol. For the hitting
+ test it is assumed the symbol is a circle of this size
+ (radius).
+ """
+ x, y = self.projected_points(layer, shape.Points())[0][0]
+ return hypot(px - x, py - y) < size and (filled or stroked)
+
+ def _hit_arc(self, layer, shape, filled, stroked, px, py):
+ """Internal: return whether a click at (px,py) hits the arc shape
+
+ The filled and stroked parameters determine whether the shape is
+ assumed to be filled or stroked respectively.
+ """
+ if not stroked:
+ return 0
+ points = self.projected_points(layer, shape.Points())
+ return hittest.arc_hit(points, px, py)
+
+ def _hit_polygon(self, layer, shape, filled, stroked, px, py):
+ """Internal: return whether a click at (px,py) hits the polygon shape
+
+ The filled and stroked parameters determine whether the shape is
+ assumed to be filled or stroked respectively.
+ """
+ points = self.projected_points(layer, shape.Points())
+ hit = hittest.polygon_hit(points, px, py)
+ if filled:
+ return bool(hit)
+ return stroked and hit < 0
+
+ def _find_label_at(self, px, py):
+ """Internal: Find the label at (px, py) and return its index
+
+ Return None if no label is hit.
+ """
+ map_proj = self.map.projection
+ if map_proj is not None:
+ forward = map_proj.Forward
+ else:
+ forward = None
+ scale = self.scale
+ offx, offy = self.offset
+
+ labels = self.map.LabelLayer().Labels()
+ if labels:
+ for i in range(len(labels) - 1, -1, -1):
+ label = labels[i]
+ x = label.x
+ y = label.y
+ text = label.text
+ if forward:
+ x, y = forward(x, y)
+ x = x * scale + offx
+ y = -y * scale + offy
+ width, height = self.GetTextExtent(text)
+ if label.halign == ALIGN_LEFT:
+ # nothing to be done
+ pass
+ elif label.halign == ALIGN_RIGHT:
+ x = x - width
+ elif label.halign == ALIGN_CENTER:
+ x = x - width/2
+ if label.valign == ALIGN_TOP:
+ # nothing to be done
+ pass
+ elif label.valign == ALIGN_BOTTOM:
+ y = y - height
+ elif label.valign == ALIGN_CENTER:
+ y = y - height/2
+ if x <= px < x + width and y <= py <= y + height:
+ return i
+ return None
+
+ def SelectShapeAt(self, x, y, layer = None):
+ """\
+ Select and return the shape and its layer at window position (x, y)
+
+ If layer is given, only search in that layer. If no layer is
+ given, search through all layers.
+
+ Return a tuple (layer, shapeid). If no shape is found, return
+ (None, None).
+ """
+ layer, shape = result = self.find_shape_at(x, y, searched_layer=layer)
+ # If layer is None, then shape will also be None. We don't want
+ # to deselect the currently selected layer, so we simply select
+ # the already selected layer again.
+ if layer is None:
+ layer = self.selection.SelectedLayer()
+ shapes = []
+ else:
+ shapes = [shape]
+ self.selection.SelectShapes(layer, shapes)
+ return result
+
+ def LabelShapeAt(self, x, y, text = None):
+ """Add or remove a label at window position x, y.
+
+ If there's a label at the given position, remove it. Otherwise
+ determine the shape at the position and add a label.
+
+ Return True is an action was performed, False otherwise.
+ """
+ label_layer = self.map.LabelLayer()
+ layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
+ if layer is None and shape_index is not None:
+ # a label was selected
+ label_layer.RemoveLabel(shape_index)
+ return True
+ elif layer is not None and text:
+ (x, y, halign, valign) = layer.GetLabelPosFromShape(self.map, \
+ shape_index)
+ label_layer.AddLabel(x, y, text,
+ halign = halign, valign = valign)
+ return True
+ return False
+
+def output_transform(canvas_scale, canvas_offset, canvas_size, device_extend):
+ """Calculate dimensions to transform canvas content to output device."""
+ width, height = device_extend
+
+ # Only 80 % of the with are available for the map
+ width = width * 0.8
+
+ # Define the distance of the map from DC border
+ distance = 20
+
+ if height < width:
+ # landscape
+ map_height = height - 2*distance
+ map_width = map_height
+ else:
+ # portrait, recalibrate width (usually the legend width is too
+ # small
+ width = width * 0.9
+ map_height = width - 2*distance
+ map_width = map_height
+
+ mapregion = (distance, distance,
+ distance+map_width, distance+map_height)
+
+ canvas_width, canvas_height = canvas_size
+
+ scalex = map_width / (canvas_width/canvas_scale)
+ scaley = map_height / (canvas_height/canvas_scale)
+ scale = min(scalex, scaley)
+ canvas_offx, canvas_offy = canvas_offset
+ offx = scale*canvas_offx/canvas_scale
+ offy = scale*canvas_offy/canvas_scale
+
+ return scale, (offx, offy), mapregion
Added: packages/thuban/branches/upstream/current/Thuban/__init__.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/__init__.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/__init__.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,132 @@
+# Copyright (c) 2001, 2003, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Jan-Oliver Wagner <jan at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+import os
+
+# Thuban Message Translation
+#
+# This is somewhat tricky. On the one hand we want to use the wx
+# facilities because that way the standard wx messages are also
+# translated and we get automatic conversion of encodings so the we can
+# use e.g. an UTF po/mo file in a Latin 1 environment. OTOH, we do not
+# want to import the wxPython modules at all when running the test suite
+# because otherwise the test suite would require a working X server
+# connection.
+#
+# Therefore this module only provides the hooks for installing the
+# correct translation function with a default translation function that
+# does nothing and simply returns the string it gets as argument.
+#
+# The front end to the installed translation function is _ (see it's
+# doc-string).
+#
+# The Thuban.UI module is responsible for installing the wx translation
+# function. It must take care to install the translation function as
+# early as possible, i.e. when Thuban/UI/__init__.py is executed so that
+# strings translated at module import time are translated (this also
+# means that a program built on top of Thuban and which uses Thuban.UI
+# should start by importing Thuban.UI before any other Thuban module.
+#
+# At the same time Thuban/UI/__init__.py should not import any wxPython
+# module unless it really has to install the translation function, i.e.
+# when no other translation function has already been installed. That
+# way the test suite can override the wx translation by installing its
+# own translation function before importing anything from Thuban.UI and
+# actually before importing anything but the Thuban module itself.
+
+# Thedirectory holding the translation files (actually they're in
+# language specific subdirectories of _message_dir)
+_message_dir = os.path.join(os.path.dirname(__file__), os.pardir, "Resources",
+ "Locale")
+
+def _(s):
+ """Return a localized version of the the string s
+
+ This is the function to use in the sources to translate strings and
+ it simply delegates the translation to the installable translation
+ function. It's done this way so that _ may be imported with 'from
+ Thuban import _' even when the correct translation function hasn't
+ been installed yet.
+ """
+ return _translation_function(s)
+
+def gettext_identity(s):
+ """Default gettext implementation which returns the string as is"""
+ return s
+
+_translation_function = gettext_identity
+
+def translation_function_installed():
+ """Return whether a translation function has been installed."""
+ return _translation_function is not gettext_identity
+
+def install_translation_function(function):
+ """Install function as the translation function
+
+ If a translation has already been installed that is not the default
+ implementation (gettext_identity) do nothing.
+ """
+ global _translation_function
+ if not translation_function_installed():
+ _translation_function = function
+
+
+
+# String representation in Thuban
+#
+# Thuban has an internal representation for textual data that all text
+# that comes into Thuban has to be converted into. Any text written by
+# Thuban has to be converted to whatever is needed by the output device.
+#
+# Currently, the internal representation is usually a byte-string in a
+# particuler encoding. For more details see the file
+# Doc/technotes/string_representation.txt.
+
+# The encoding to use for the internal string representation. Usually
+# it's a string with the encoding name to use when converting between
+# Python byte-strings and unicode objects. The special value "unicode"
+# means the use unicode objects as the internal representation.
+_internal_encoding = None
+
+def internal_from_unicode(unistr):
+ """Return Thuban's internal representation for the unicode object unistr"""
+ if _internal_encoding != "unicode":
+ # we use replace so that we don't get exceptions when the
+ # conversion can't be done properly.
+ return unistr.encode(_internal_encoding, "replace")
+ else:
+ return unistr
+
+def unicode_from_internal(s):
+ """Return the unicode object for the string s in internal representation"""
+ if _internal_encoding != "unicode":
+ return unicode(s, _internal_encoding)
+ else:
+ return s
+
+
+def set_internal_encoding(encoding):
+ """Set the encoding to use for the internal string representation
+
+ The parameter should be the name of an encoding known to Python so
+ that it can be used with e.g. the encode method of unicode objects.
+ As a special case it can be the string 'unicode' to indicate that
+ the internal representation are unicode objects.
+ """
+ global _internal_encoding
+ _internal_encoding = encoding
+
+ # and now let us test, if we can go back and forth
+ # it is better to complain now than to have runtime problems later
+ unicode_from_internal(internal_from_unicode(u''))
+
+def get_internal_encoding():
+ """Return the encoding used for Thuban's internal string representation."""
+ global _internal_encoding
+ return _internal_encoding
Added: packages/thuban/branches/upstream/current/Thuban/version.py
===================================================================
--- packages/thuban/branches/upstream/current/Thuban/version.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/Thuban/version.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,203 @@
+# Copyright (C) 2002, 2003, 2004 by Intevation GmbH
+# Authors:
+# Thomas Koester <tkoester at intevation.de>
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""
+Thuban version information
+"""
+
+__version__ = "$Revision: 2729 $"
+# $Source$
+# $Id: version.py 2729 2007-02-20 10:52:38Z bernhard $
+
+
+# Note that this file defines the version number of Thuban for the about
+# dialog.
+
+# The thuban version string is build from two values, thuban_branch and
+# thuban_release. If release is "cvs" the code is from a non-released
+# cvs version and the version string is built from the branch, the
+# release and an approximation of the date (e.g. the most recent date of
+# the ChangeLog file or the most recent modification time of a source
+# file). Otherwise the string is build from the branch and the release.
+# E.g. given
+#
+# thuban_branch = "1.1"
+# thuban_release = "svn"
+#
+# the version string will be "Thuban 1.1 svn-20040224" (obviously the
+# actual date might differ :) ). OTOH, given
+#
+# thuban_branch = "1.0"
+# thuban_release = "1"
+#
+# the version string will be "Thuban 1.0.1"
+#
+
+thuban_branch = "1.2"
+thuban_release = "0"
+
+
+
+import sys, os, os.path
+import time
+from string import split
+
+from Thuban import _
+from Thuban.Lib.version import make_tuple
+
+if __name__ == "__main__":
+ import sys
+ __file__ = sys.argv[0]
+
+def is_relevant_file(file):
+ """check if a file is relevant for determining the current version"""
+ extensions = ['.py', '.xpm', '.c', '.h']
+ return os.path.isfile(file) and os.path.splitext(file)[1] in extensions
+
+def visit(args, dirname, names):
+ """helper for os.path.walk; save mtime of newest file for this directory"""
+ files = filter(is_relevant_file,
+ [os.path.join(dirname, file) for file in names])
+ args['max'] = max([args['max']] + map(os.path.getmtime, files))
+
+def get_date(format):
+ """strftime formatted mtime of the newest relevant file"""
+ dir = os.path.dirname(os.path.abspath(__file__))
+ args = {'max': 0}
+ os.path.walk(dir, visit, args)
+ return time.strftime(format, time.localtime(args['max']))
+
+def get_changelog_date():
+ changelog = os.path.join(os.path.dirname(__file__), os.pardir, "ChangeLog")
+ try:
+ file = open(changelog, "r")
+ line = file.readline()
+ file.close()
+ except:
+ return ""
+ return 'ChangeLog %s' % line.split(" ")[0]
+
+
+#
+# Fill in versions with the different versions of the libraries
+# that Thuban is using or requires (only if those libraries are
+# available.
+#
+
+versions = {}
+
+if thuban_release == "svn":
+ version = '%s %s-%s' % (thuban_branch, thuban_release, get_date('%Y%m%d'))
+ longversion = '%s\n%s' % (version, get_changelog_date())
+else:
+ version = thuban_branch + "." + thuban_release
+ longversion = 'Release Version ' + version
+
+versions['thuban'] = version
+versions['thuban-long'] = longversion
+
+# wxPython
+
+from wx import __version__ as wxPython_version
+versions['wxPython'] = wxPython_version
+versions['wxPython-tuple'] = make_tuple(wxPython_version)
+
+# Python
+versions['python'] = "%d.%d.%d" % sys.version_info[:3]
+versions['python-tuple'] = sys.version_info[:3]
+
+# PySQLite
+try:
+ from pysqlite2 import dbapi2 as sqlite
+except ImportError:
+ import sqlite
+versions['pysqlite'] = sqlite.version
+versions['pysqlite-tuple'] = make_tuple(sqlite.version)
+
+# SQLite
+try:
+ from pysqlite2._sqlite import sqlite_version
+ versions['sqlite'] = sqlite_version
+ versions['sqlite-tuple'] = make_tuple(sqlite_version)
+except ImportError:
+ from _sqlite import sqlite_version
+ versions['sqlite'] = sqlite_version()
+ versions['sqlite-tuple'] = make_tuple(sqlite_version())
+
+# GDAL
+from Thuban.Model.resource import has_gdal_support
+if has_gdal_support():
+ from gdalwarp import get_gdal_version
+ versions['gdal'] = get_gdal_version()
+ versions['gdal-tuple'] = make_tuple(get_gdal_version())
+
+from wxproj import get_proj_version, get_gtk_version, get_wx_version
+
+# GTK
+gtk_ver = get_gtk_version()
+if gtk_ver:
+ versions['gtk'] = ".".join(map(str, gtk_ver))
+ versions['gtk-tuple'] = gtk_ver
+
+# PROJ
+proj_ver = get_proj_version()
+if proj_ver:
+ versions['proj'] = ".".join(map(str, proj_ver))
+ versions['proj-tuple'] = proj_ver
+
+wxproj_wx_version = get_wx_version()
+versions['wxproj-wx'] = ".".join(map(str, wxproj_wx_version))
+versions['wxproj-wx-tuple'] = wxproj_wx_version
+
+
+# psycopg/postgis
+import Thuban.Model.postgisdb
+if Thuban.Model.postgisdb.has_postgis_support():
+ v = Thuban.Model.postgisdb.psycopg_version()
+ versions['psycopg'] = v
+ versions['psycopg-tuple'] = make_tuple(v)
+
+def verify_versions():
+ """Verify that Thuban is using the correct versions of libraries.
+
+ Returns a non-empty list of strings indicating which libraries
+ are wrong, or the empty list if everthing is ok.
+ """
+
+ #
+ # The 'name' below must correspong to an mapping in 'versions'.
+ # There must also exist a 'name'-tuple mapping.
+ #
+ # title name version
+ list = [["Python", "python", (2, 2, 1)],
+ ["wxPython", "wxPython", (2, 4, 0)],
+ ["SQLite", "sqlite", (2, 8, 0)],
+ ["PySQLite", "pysqlite", (0, 4, 1)],
+ ["PROJ", "proj", (4, 4, 5)],
+ ["GTK", "gtk", (1, 2, 3)],
+ ["GDAL", "gdal", (1, 1, 8)]]
+
+ errors = []
+ for title, name, version in list:
+ tup = versions.get("%s-tuple" % name, None)
+ if tup and tup < version:
+ errors.append(_("%s %s < %s") % \
+ (title, versions[name], ".".join(map(str, version))))
+
+ # Check whether the wxWindows version of wxPython and thuban's
+ # wxproj module match. If they don't match, segfaults are likely.
+ if versions["wxproj-wx-tuple"] != versions["wxPython-tuple"][:3]:
+ errors.append(_("Thuban was compiled with wx %(wxproj-wx)s"
+ " but wxPython is %(wxPython)s")
+ % versions)
+
+ return errors
+
+if __name__ == "__main__":
+ print longversion
+
Added: packages/thuban/branches/upstream/current/devtools/create_epsg.py
===================================================================
--- packages/thuban/branches/upstream/current/devtools/create_epsg.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/devtools/create_epsg.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,56 @@
+# Copyright (c) 2003 by Intevation GmbH
+# Authors:
+# Jan-Oliver Wagner <jan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Convert the epsg file of proj into a python .proj file.
+
+Call it like:
+$ python create_epsg.py > epsg.proj
+
+This tool assumes the original file of proj ('epsg') to
+be present in the standard location of a system wide
+installation, i.e. in /usr/share/proj/epsg.
+If it is somewhere else, just adapt the path in the code
+below.
+
+The entries in the source file look like this:
+
+# Anguilla 1957 / British West Indies Grid
+<200> +proj=tmerc +lat_0=0.000000000 +lon_0=-62.000000000 +k=0.999500 +x_0=40000 0.000 +y_0=0.000 +ellps=clrk80 +units=m no_defs <>
+"""
+
+__version__ = "$Revision: 1800 $"
+
+# this function is copied from Thuban/Model/xmlwriter.py
+def escape(data):
+ """Escape &, \", ', <, and > in a string of data.
+ """
+ data = data.replace("&", "&")
+ data = data.replace("<", "<")
+ data = data.replace(">", ">")
+ data = data.replace('"', """)
+ data = data.replace("'", "'")
+ return data
+
+print '<?xml version="1.0" encoding="UTF-8"?>'
+print '<!DOCTYPE projfile SYSTEM "projectionlist.dtd">'
+print '<projectionlist>'
+
+epsg = open('/usr/share/proj/epsg', 'r').readlines()
+
+for line in epsg:
+ if line[0] == '#':
+ title = line[2:-1]
+ if line[0] == '<':
+ elements = line.split(' ')
+ epsg_nr = elements[0][1:-1]
+ print ' <projection epsg="%s" name="%s">' % (epsg_nr, escape(title))
+ for p in elements[1:-3]:
+ print ' <parameter value="%s"/>' % escape(p[1:])
+ print ' </projection>'
+
+print '</projectionlist>'
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/LICENSE
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/LICENSE 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/LICENSE 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,27 @@
+Projection.i: SWIG interface file for PROJ.4 projection library.
+
+Copyright (c) 2001 Meridian Environmental Technology, Inc
+All rights reserved.
+
+Author: Douglas K. Rand <rand at meridian-enviro.com>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/MANIFEST.in
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/MANIFEST.in 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/MANIFEST.in 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,2 @@
+include *.i
+include *.txt Makefile *.pth
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.i
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.i 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.i 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,229 @@
+// This looks most like -*- c -*- code
+
+//
+// Projection.i: SWIG interface file for PROJ.4 projection library.
+//
+// Copyright (c) 2001 Meridian Environmental Technology, Inc
+// All rights reserved.
+//
+// Author: Douglas K. Rand <rand at meridian-enviro.com>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+//
+
+
+%module Projection
+%{
+#include <projects.h>
+
+ // We wrap the PJ structure in our own so we can keep the
+ // type of units the user wants to operate in along.
+ typedef enum {DEGREES, RADIANS} Units;
+ typedef struct {
+ Units units;
+ PJ *proj;
+ } Projection;
+%}
+
+%include typemaps.i
+%include constraints.i
+%include array.i
+
+typedef enum {DEGREES, RADIANS} Units;
+
+// Because that stupid pj_init() function requires a count of the args,
+// we have to do a typemap for EACH language terminating it with a null
+// so we can count the items in our wrapper. Sigh.
+%typemap(python, in) char **argv {
+ /* Check if is a list */
+ if (PyList_Check($source)) {
+ int size = PyList_Size($source);
+ int i = 0;
+ $target = (char **) malloc((size+1)*sizeof(char *));
+ for (i = 0; i < size; i++) {
+ PyObject *o = PyList_GetItem($source,i);
+ if (PyString_Check(o))
+ $target[i] = PyString_AsString(PyList_GetItem($source,i));
+ else {
+ PyErr_SetString(PyExc_TypeError,"list must contain strings");
+ free($target);
+ return NULL;
+ }
+ }
+ $target[i] = 0;
+ } else {
+ PyErr_SetString(PyExc_TypeError,"not a list"); return NULL;
+ }
+}
+
+// Free up the argv structure created above
+%typemap(python, freearg) char **argv {
+ free((char *) $source);
+}
+
+/* Assign the pointer to a local variable */
+%typemap(python, ignore) double *outvalue(double temp) {
+ $target = &temp;
+}
+
+// This tells SWIG to treat an double * argument with name 'outvalue' as
+// an output value. We'll append the value to the current result which
+// is guaranteed to be a List object by SWIG.
+%typemap(python,argout) double *outvalue {
+ PyObject *o;
+ o = PyFloat_FromDouble(*$source);
+ if ((!$target) || ($target == Py_None)) {
+ $target = o;
+ } else {
+ if (!PyList_Check($target)) {
+ PyObject *o2 = $target;
+ $target = PyList_New(0);
+ PyList_Append($target,o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append($target,o);
+ Py_XDECREF(o);
+ }
+}
+
+//%typemap(perl5, argout) double *outvalue {
+// $target = sv_newmortal();
+// sv_setnv($target, *$source);
+// argvi++;
+//}
+
+/* Assign the pointer to a local variable */
+%typemap(python,in) double *outvalue {
+ static double junk;
+ $target = &junk;
+}
+
+//%typemap(perl5, in) double *outvalue {
+// static double junk;
+// $target = &junk;
+//}
+
+
+/* Exception handler for the Projection constructor */
+%typemap(python,except) Projection * {
+ /* Use pj_get_errno_ref to access the pj_errno because directly
+ * accessing pj_errno doesn't work on windows if the proj library is
+ * in a DLL */
+ *pj_get_errno_ref() = 0;
+ $function;
+ if (!$source)
+ {
+ /* FIXME: There's a case where $source is NULL and pj_errno is
+ * not set, namely when memory allocation of the Projection
+ * struct fails. */
+ SWIG_exception(SWIG_IOError, pj_strerrno(*pj_get_errno_ref()));
+ }
+}
+
+
+typedef struct {
+ Units units;
+ PJ *proj;
+
+ %addmethods {
+ Projection(char **argv, Units units = DEGREES);
+ ~Projection();
+ void Forward(double lat, double lon, double *outvalue, double *outvalue);
+ void Inverse(double u, double v, double *outvalue, double *outvalue);
+
+ PyObject * cobject() {
+ return PyCObject_FromVoidPtr(self->proj, NULL);
+ }
+
+
+ /* The __del__ method generated by the old SWIG version we're
+ * tries to access self.thisown which may not be set at all when
+ * there was an exception during construction. Therefore we
+ * override it with our own version.
+ * FIXME: It would be better to upgrade to a newer SWIG version
+ * or to get rid of SWIG entirely.
+ */
+ %pragma(python) addtoclass = "
+ def __del__(self,Projectionc=Projectionc):
+ if getattr(self, 'thisown', 0):
+ Projectionc.delete_Projection(self)
+ "
+
+ }
+} Projection;
+
+%{
+ // Make a brand new projection
+ Projection *new_Projection(char **argv, Units units) {
+ int argc = 0;
+ char **p;
+ PJ *proj;
+ Projection *pj = NULL;
+
+ for(p = argv; p != NULL && *p != NULL; p++) argc++;
+ proj = pj_init(argc, argv);
+ if(proj != NULL) {
+ pj = (Projection *) malloc(sizeof(Projection));
+ pj->units = units;
+ pj->proj = proj;
+ }
+ return pj;
+ }
+
+ // Get rid of a projection
+ void delete_Projection(Projection *self) {
+ if(self != NULL) {
+ if(self->proj != NULL)
+ pj_free(self->proj);
+ free(self);
+ }
+ }
+
+ // Do a forward (lat/lon --> world) translation
+ void Projection_Forward(Projection *self, double lat, double lon, double *u, double *v) {
+ projUV latlon, result;
+ latlon.u = lat;
+ latlon.v = lon;
+ if(self->units == DEGREES) {
+ latlon.u *= DEG_TO_RAD;
+ latlon.v *= DEG_TO_RAD;
+ }
+ result = pj_fwd(latlon, self->proj);
+ *u = result.u;
+ *v = result.v;
+ }
+
+ // Do a reverse (world --> lat/lon) translation
+ void Projection_Inverse(Projection *self, double u, double v, double *lat, double *lon) {
+ projUV world, result;
+ world.u = u;
+ world.v = v;
+ result = pj_inv(world, self->proj);
+ if(self->units == DEGREES) {
+ result.u *= RAD_TO_DEG;
+ result.v *= RAD_TO_DEG;
+ }
+ *lat = result.u;
+ *lon = result.v;
+ }
+%}
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/Projection.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,93 @@
+# This file was created automatically by SWIG.
+import Projectionc
+class Projection:
+ def __init__(self,*args):
+ self.this = apply(Projectionc.new_Projection,args)
+ self.thisown = 1
+
+ def __del__(self,Projectionc=Projectionc):
+ if self.thisown == 1 :
+ Projectionc.delete_Projection(self)
+ def Forward(*args):
+ val = apply(Projectionc.Projection_Forward,args)
+ return val
+ def Inverse(*args):
+ val = apply(Projectionc.Projection_Inverse,args)
+ return val
+ def cobject(*args):
+ val = apply(Projectionc.Projection_cobject,args)
+ return val
+ __setmethods__ = {
+ "units" : Projectionc.Projection_units_set,
+ "proj" : Projectionc.Projection_proj_set,
+ }
+ def __setattr__(self,name,value):
+ if (name == "this") or (name == "thisown"): self.__dict__[name] = value; return
+ method = Projection.__setmethods__.get(name,None)
+ if method: return method(self,value)
+ self.__dict__[name] = value
+ __getmethods__ = {
+ "units" : Projectionc.Projection_units_get,
+ "proj" : Projectionc.Projection_proj_get,
+ }
+ def __getattr__(self,name):
+ method = Projection.__getmethods__.get(name,None)
+ if method: return method(self)
+ raise AttributeError,name
+ def __repr__(self):
+ return "<C Projection instance at %s>" % (self.this,)
+
+ def __del__(self,Projectionc=Projectionc):
+ if getattr(self, 'thisown', 0):
+ Projectionc.delete_Projection(self)
+
+class ProjectionPtr(Projection):
+ def __init__(self,this):
+ self.this = this
+ self.thisown = 0
+ self.__class__ = Projection
+
+
+
+
+
+#-------------- FUNCTION WRAPPERS ------------------
+
+int_array = Projectionc.int_array
+
+int_destroy = Projectionc.int_destroy
+
+int_get = Projectionc.int_get
+
+int_set = Projectionc.int_set
+
+double_array = Projectionc.double_array
+
+double_destroy = Projectionc.double_destroy
+
+double_get = Projectionc.double_get
+
+double_set = Projectionc.double_set
+
+float_array = Projectionc.float_array
+
+float_destroy = Projectionc.float_destroy
+
+float_get = Projectionc.float_get
+
+float_set = Projectionc.float_set
+
+string_array = Projectionc.string_array
+
+string_destroy = Projectionc.string_destroy
+
+string_get = Projectionc.string_get
+
+string_set = Projectionc.string_set
+
+
+
+#-------------- VARIABLE WRAPPERS ------------------
+
+DEGREES = Projectionc.DEGREES
+RADIANS = Projectionc.RADIANS
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/Projection_wrap.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/Projection_wrap.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/Projection_wrap.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1549 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3u-20020503-1857 (Alpha 5)
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPYTHON
+/***********************************************************************
+ * common.swg
+ *
+ * This file contains generic SWIG runtime support for pointer
+ * type checking as well as a few commonly used macros to control
+ * external linkage.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ *
+ * Copyright (c) 1999-2000, The University of Chicago
+ *
+ * This file may be freely redistributed without license or fee provided
+ * this copyright message remains intact.
+ ************************************************************************/
+
+#include <string.h>
+
+#if defined(_WIN32) || defined(__WIN32__)
+# if defined(_MSC_VER)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT(a) a
+# else
+# define SWIGEXPORT(a) __declspec(dllexport) a
+# endif
+# else
+# if defined(__BORLANDC__)
+# define SWIGEXPORT(a) a _export
+# else
+# define SWIGEXPORT(a) a
+# endif
+#endif
+#else
+# define SWIGEXPORT(a) a
+#endif
+
+#ifdef SWIG_GLOBAL
+#define SWIGRUNTIME(a) SWIGEXPORT(a)
+#else
+#define SWIGRUNTIME(a) static a
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct swig_type_info {
+ char *name;
+ void *(*converter)(void *);
+ char *str;
+ struct swig_type_info *next;
+ struct swig_type_info *prev;
+} swig_type_info;
+
+#ifdef SWIG_NOINCLUDE
+SWIGEXPORT(swig_type_info *) SWIG_TypeRegister(swig_type_info *);
+SWIGEXPORT(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *);
+SWIGEXPORT(void *) SWIG_TypeCast(swig_type_info *, void *);
+#else
+
+static swig_type_info *swig_type_list = 0;
+
+/* Register a type mapping with the type-checking */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeRegister(swig_type_info *ti)
+{
+ swig_type_info *tc, *head, *ret, *next;
+ /* Check to see if this type has already been registered */
+ tc = swig_type_list;
+ while (tc) {
+ if (strcmp(tc->name, ti->name) == 0) {
+ /* Already exists in the table. Just add additional types to the list */
+ head = tc;
+ next = tc->next;
+ goto l1;
+ }
+ tc = tc->prev;
+ }
+ head = ti;
+ next = 0;
+
+ /* Place in list */
+ ti->prev = swig_type_list;
+ swig_type_list = ti;
+
+ /* Build linked lists */
+ l1:
+ ret = head;
+ tc = ti + 1;
+ /* Patch up the rest of the links */
+ while (tc->name) {
+ head->next = tc;
+ tc->prev = head;
+ head = tc;
+ tc++;
+ }
+ head->next = next;
+ return ret;
+}
+
+/* Check the typename */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeCheck(char *c, swig_type_info *ty)
+{
+ swig_type_info *s;
+ if (!ty) return 0; /* Void pointer */
+ s = ty->next; /* First element always just a name */
+ while (s) {
+ if (strcmp(s->name,c) == 0) {
+ if (s == ty->next) return s;
+ /* Move s to the top of the linked list */
+ s->prev->next = s->next;
+ if (s->next) {
+ s->next->prev = s->prev;
+ }
+ /* Insert s as second element in the list */
+ s->next = ty->next;
+ if (ty->next) ty->next->prev = s;
+ ty->next = s;
+ return s;
+ }
+ s = s->next;
+ }
+ return 0;
+}
+
+/* Cast a pointer (needed for C++ inheritance */
+SWIGRUNTIME(void *)
+SWIG_TypeCast(swig_type_info *ty, void *ptr)
+{
+ if ((!ty) || (!ty->converter)) return ptr;
+ return (*ty->converter)(ptr);
+}
+
+/* Search for a swig_type_info structure */
+SWIGRUNTIME(void *)
+SWIG_TypeQuery(const char *name) {
+ swig_type_info *ty = swig_type_list;
+ while (ty) {
+ if (ty->str && (strcmp(name,ty->str) == 0)) return ty;
+ if (ty->name && (strcmp(name,ty->name) == 0)) return ty;
+ ty = ty->prev;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/***********************************************************************
+ * python.swg
+ *
+ * This file contains the runtime support for Python modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ ************************************************************************/
+
+#include <stdlib.h>
+#include "Python.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_PY_INT 1
+#define SWIG_PY_FLOAT 2
+#define SWIG_PY_STRING 3
+#define SWIG_PY_POINTER 4
+
+/* Constant information structure */
+typedef struct swig_const_info {
+ int type;
+ char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_const_info;
+
+#ifdef SWIG_NOINCLUDE
+
+SWIGEXPORT(PyObject *) SWIG_newvarlink();
+SWIGEXPORT(void) SWIG_addvarlink(PyObject *, char *, PyObject *(*)(void), int (*)(PyObject *));
+SWIGEXPORT(int) SWIG_ConvertPtr(PyObject *, void **, swig_type_info *, int);
+SWIGEXPORT(void) SWIG_MakePtr(char *c, void *, swig_type_info *);
+SWIGEXPORT(PyObject *) SWIG_NewPointerObj(void *, swig_type_info *);
+SWIGEXPORT(void) SWIG_InstallConstants(PyObject *d, swig_const_info constants[]);
+
+#else
+
+/* -----------------------------------------------------------------------------
+ * global variable support code.
+ * ----------------------------------------------------------------------------- */
+
+typedef struct swig_globalvar {
+ char *name; /* Name of global variable */
+ PyObject *(*get_attr)(void); /* Return the current value */
+ int (*set_attr)(PyObject *); /* Set the value */
+ struct swig_globalvar *next;
+} swig_globalvar;
+
+typedef struct swig_varlinkobject {
+ PyObject_HEAD
+ swig_globalvar *vars;
+} swig_varlinkobject;
+
+static PyObject *
+swig_varlink_repr(swig_varlinkobject *v) {
+ v = v;
+ return PyString_FromString("<Global variables>");
+}
+
+static int
+swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) {
+ swig_globalvar *var;
+ flags = flags;
+ fprintf(fp,"Global variables { ");
+ for (var = v->vars; var; var=var->next) {
+ fprintf(fp,"%s", var->name);
+ if (var->next) fprintf(fp,", ");
+ }
+ fprintf(fp," }\n");
+ return 0;
+}
+
+static PyObject *
+swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->get_attr)();
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return NULL;
+}
+
+static int
+swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->set_attr)(p);
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return 1;
+}
+
+statichere PyTypeObject varlinktype = {
+ PyObject_HEAD_INIT(0)
+ 0,
+ "swigvarlink", /* Type name */
+ sizeof(swig_varlinkobject), /* Basic size */
+ 0, /* Itemsize */
+ 0, /* Deallocator */
+ (printfunc) swig_varlink_print, /* Print */
+ (getattrfunc) swig_varlink_getattr, /* get attr */
+ (setattrfunc) swig_varlink_setattr, /* Set attr */
+ 0, /* tp_compare */
+ (reprfunc) swig_varlink_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_mapping*/
+ 0, /* tp_hash */
+};
+
+/* Create a variable linking object for use later */
+SWIGRUNTIME(PyObject *)
+SWIG_newvarlink(void) {
+ swig_varlinkobject *result = 0;
+ result = PyMem_NEW(swig_varlinkobject,1);
+ varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */
+ result->ob_type = &varlinktype;
+ result->vars = 0;
+ result->ob_refcnt = 0;
+ Py_XINCREF((PyObject *) result);
+ return ((PyObject*) result);
+}
+
+SWIGRUNTIME(void)
+SWIG_addvarlink(PyObject *p, char *name,
+ PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+ swig_varlinkobject *v;
+ swig_globalvar *gv;
+ v= (swig_varlinkobject *) p;
+ gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+ gv->name = (char *) malloc(strlen(name)+1);
+ strcpy(gv->name,name);
+ gv->get_attr = get_attr;
+ gv->set_attr = set_attr;
+ gv->next = v->vars;
+ v->vars = gv;
+}
+/* Convert a pointer value */
+SWIGRUNTIME(int)
+SWIG_ConvertPtr(PyObject *obj, void **ptr, swig_type_info *ty, int flags) {
+ unsigned long p;
+ register int d;
+ swig_type_info *tc;
+ char *c;
+ static PyObject *SWIG_this = 0;
+ int newref = 0;
+
+ if (!obj || (obj == Py_None)) {
+ *ptr = 0;
+ return 0;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ if (!(PyCObject_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyCObject_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ *ptr = PyCObject_AsVoidPtr(obj);
+ c = (char *) PyCObject_GetDesc(obj);
+ if (newref) Py_DECREF(obj);
+ goto cobject;
+#else
+ if (!(PyString_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyString_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c = PyString_AsString(obj);
+ p = 0;
+ /* Pointer values must start with leading underscore */
+ if (*c != '_') {
+ *ptr = (void *) 0;
+ if (strcmp(c,"NULL") == 0) {
+ if (newref) Py_DECREF(obj);
+ return 0;
+ } else {
+ if (newref) Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c++;
+ /* Extract hex value from pointer */
+ while ((d = *c)) {
+ if ((d >= '0') && (d <= '9'))
+ p = (p << 4) + (d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ p = (p << 4) + (d - ('a'-10));
+ else
+ break;
+ c++;
+ }
+ *ptr = (void *) p;
+ if (newref) Py_DECREF(obj);
+#endif
+
+#ifdef SWIG_COBJECT_TYPES
+cobject:
+#endif
+
+ if (ty) {
+ tc = SWIG_TypeCheck(c,ty);
+ if (!tc) goto type_error;
+ *ptr = SWIG_TypeCast(tc,(void*)p);
+ }
+ return 0;
+
+type_error:
+
+ if (flags) {
+ if (ty) {
+ char *temp = (char *) malloc(64+strlen(ty->name));
+ sprintf(temp,"Type error. Expected %s", ty->name);
+ PyErr_SetString(PyExc_TypeError, temp);
+ free((char *) temp);
+ } else {
+ PyErr_SetString(PyExc_TypeError,"Expected a pointer");
+ }
+ }
+ return -1;
+}
+
+/* Take a pointer and convert it to a string */
+SWIGRUNTIME(void)
+SWIG_MakePtr(char *c, void *ptr, swig_type_info *ty) {
+ static char hex[17] = "0123456789abcdef";
+ unsigned long p, s;
+ char result[32], *r;
+ r = result;
+ p = (unsigned long) ptr;
+ if (p > 0) {
+ while (p > 0) {
+ s = p & 0xf;
+ *(r++) = hex[s];
+ p = p >> 4;
+ }
+ *r = '_';
+ while (r >= result)
+ *(c++) = *(r--);
+ strcpy (c, ty->name);
+ } else {
+ strcpy (c, "NULL");
+ }
+}
+
+/* Create a new pointer object */
+SWIGRUNTIME(PyObject *)
+SWIG_NewPointerObj(void *ptr, swig_type_info *type) {
+ char result[512];
+ PyObject *robj;
+ if (!ptr) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ robj = PyCObject_FromVoidPtrAndDesc((void *) ptr, type->name, NULL);
+#else
+ SWIG_MakePtr(result,ptr,type);
+ robj = PyString_FromString(result);
+#endif
+ return robj;
+}
+
+/* Install Constants */
+SWIGRUNTIME(void)
+SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) {
+ int i;
+ PyObject *obj;
+ for (i = 0; constants[i].type; i++) {
+ switch(constants[i].type) {
+ case SWIG_PY_INT:
+ obj = PyInt_FromLong(constants[i].lvalue);
+ break;
+ case SWIG_PY_FLOAT:
+ obj = PyFloat_FromDouble(constants[i].dvalue);
+ break;
+ case SWIG_PY_STRING:
+ obj = PyString_FromString((char *) constants[i].pvalue);
+ break;
+ case SWIG_PY_POINTER:
+ obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype);
+ break;
+ default:
+ obj = 0;
+ break;
+ }
+ if (obj) {
+ PyDict_SetItemString(d,constants[i].name,obj);
+ Py_DECREF(obj);
+ }
+ }
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_float swig_types[0]
+#define SWIGTYPE_p_double swig_types[1]
+#define SWIGTYPE_p_p_char swig_types[2]
+#define SWIGTYPE_p_PJ swig_types[3]
+#define SWIGTYPE_p_int swig_types[4]
+#define SWIGTYPE_p_Projection swig_types[5]
+static swig_type_info *swig_types[7];
+
+/* -------- TYPES TABLE (END) -------- */
+
+
+/*-----------------------------------------------
+ @(target):= Projectionc.so
+ ------------------------------------------------*/
+#define SWIG_init initProjectionc
+
+#define SWIG_name "Projectionc"
+
+#include <projects.h>
+
+ // We wrap the PJ structure in our own so we can keep the
+ // type of units the user wants to operate in along.
+ typedef enum {DEGREES, RADIANS} Units;
+ typedef struct {
+ Units units;
+ PJ *proj;
+ } Projection;
+
+static PyObject* l_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyList_Check(target)) {
+ o2 = target;
+ target = PyList_New(0);
+ PyList_Append(target, o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(target,o);
+ Py_XDECREF(o);
+ }
+ return target;
+}
+
+static PyObject* t_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ PyObject* o3;
+
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyTuple_Check(target)) {
+ o2 = target;
+ target = PyTuple_New(1);
+ PyTuple_SetItem(target, 0, o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SetItem(o3, 0, o);
+
+ o2 = target;
+ target = PySequence_Concat(o2, o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+ return target;
+}
+
+#define SWIG_MemoryError 1
+#define SWIG_IOError 2
+#define SWIG_RuntimeError 3
+#define SWIG_IndexError 4
+#define SWIG_TypeError 5
+#define SWIG_DivisionByZero 6
+#define SWIG_OverflowError 7
+#define SWIG_SyntaxError 8
+#define SWIG_ValueError 9
+#define SWIG_SystemError 10
+#define SWIG_UnknownError 99
+
+static void _SWIG_exception(int code, char *msg) {
+ switch(code) {
+ case SWIG_MemoryError:
+ PyErr_SetString(PyExc_MemoryError,msg);
+ break;
+ case SWIG_IOError:
+ PyErr_SetString(PyExc_IOError,msg);
+ break;
+ case SWIG_RuntimeError:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ case SWIG_IndexError:
+ PyErr_SetString(PyExc_IndexError,msg);
+ break;
+ case SWIG_TypeError:
+ PyErr_SetString(PyExc_TypeError,msg);
+ break;
+ case SWIG_DivisionByZero:
+ PyErr_SetString(PyExc_ZeroDivisionError,msg);
+ break;
+ case SWIG_OverflowError:
+ PyErr_SetString(PyExc_OverflowError,msg);
+ break;
+ case SWIG_SyntaxError:
+ PyErr_SetString(PyExc_SyntaxError,msg);
+ break;
+ case SWIG_ValueError:
+ PyErr_SetString(PyExc_ValueError,msg);
+ break;
+ case SWIG_SystemError:
+ PyErr_SetString(PyExc_SystemError,msg);
+ break;
+ default:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ }
+}
+
+#define SWIG_exception(a,b) { _SWIG_exception(a,b); return NULL; }
+
+#include <limits.h>
+
+/* Create a new integer array */
+
+ static int *int_array(int size) {
+#ifdef __cplusplus
+ return new int[size];
+#else
+ return (int *) malloc(size*sizeof(int));
+#endif
+ }
+
+ /* Destroy an integer array */
+
+ static void int_destroy(int *array) {
+ if (array) {
+#ifdef __cplusplus
+ delete [] array;
+#else
+ free(array);
+#endif
+ }
+ }
+
+ /* Return an element */
+
+ static int int_get(int *array, int index) {
+ if (array) {
+ return array[index];
+ } else {
+ return INT_MIN;
+ }
+ }
+
+ /* Set an element */
+
+ static int int_set(int *array, int index, int value) {
+ if (array) {
+ return (array[index] = value);
+ } else {
+ return INT_MIN;
+ }
+ }
+
+
+ #include <float.h>
+
+ /* Create a new float array */
+
+ static float *float_array(int size) {
+#ifdef __cplusplus
+ return new float[size];
+#else
+ return (float *) malloc(size*sizeof(float));
+#endif
+ }
+
+ /* Destroy an array */
+
+ static void float_destroy(float *array) {
+ if (array) {
+#ifdef __cplusplus
+ delete [] array;
+#else
+ free(array);
+#endif
+ }
+ }
+
+ /* Return an element */
+
+ static float float_get(float *array, int index) {
+ if (array) {
+ return array[index];
+ } else {
+ return FLT_MIN;
+ }
+ }
+
+ /* Set an element */
+
+ static float float_set(float *array, int index, float value) {
+ if (array) {
+ return (array[index] = value);
+ } else {
+ return FLT_MIN;
+ }
+ }
+
+ /* Create a new double array */
+
+ static double *double_array(int size) {
+#ifdef __cplusplus
+ return new double[size];
+#else
+ return (double *) malloc(size*sizeof(double));
+#endif
+ }
+
+ /* Destroy an array */
+
+ static void double_destroy(double *array) {
+ if (array) {
+#ifdef __cplusplus
+ delete [] array;
+#else
+ free(array);
+#endif
+ }
+ }
+
+ /* Return an element */
+
+ static double double_get(double *array, int index) {
+ if (array) {
+ return array[index];
+ } else {
+ return FLT_MIN;
+ }
+ }
+
+ /* Set an element */
+
+ static double double_set(double *array, int index, double value) {
+ if (array) {
+ return (array[index] = value);
+ } else {
+ return FLT_MIN;
+ }
+ }
+
+
+/* Create character string arrays */
+
+static char **string_array(int size) {
+ char **a;
+ int i;
+#ifdef __cplusplus
+ a = new char *[size];
+#else
+ a = (char **) malloc(size*sizeof(char *));
+#endif
+ for (i = 0; i < size; i++)
+ a[i] = 0;
+ return a;
+}
+
+/* Destroy a string array */
+
+static void string_destroy(char **array) {
+ int i = 0;
+ if (array) {
+ while (array[i]) {
+#ifdef __cplusplus
+ delete array[i];
+#else
+ free(array[i]);
+#endif
+ i++;
+ }
+#ifdef __cplusplus
+ delete [] array;
+#else
+ free(array);
+#endif
+ }
+}
+
+/* Get an element */
+
+static char *string_get(char **array_string, int index) {
+ if (array_string)
+ if (array_string[index]) return (array_string[index]);
+ else return "";
+ else
+ return "";
+}
+
+/* Set an element */
+
+static char *string_set(char **array_string, int index, char * val) {
+ if (array_string) {
+ if (array_string[index]) {
+#ifdef __cplusplus
+ delete array_string[index];
+#else
+ free(array_string[index]);
+#endif
+ }
+ if (strlen(val) > 0) {
+#ifdef __cplusplus
+ array_string[index] = new char[strlen(val)+1];
+#else
+ array_string[index] = (char *) malloc(strlen(val)+1);
+#endif
+ strcpy(array_string[index],val);
+ return array_string[index];
+ } else {
+ array_string[index] = 0;
+ return val;
+ }
+ } else return val;
+}
+
+
+ // Make a brand new projection
+ Projection *new_Projection(char **argv, Units units) {
+ int argc = 0;
+ char **p;
+ PJ *proj;
+ Projection *pj = NULL;
+
+ for(p = argv; p != NULL && *p != NULL; p++) argc++;
+ proj = pj_init(argc, argv);
+ if(proj != NULL) {
+ pj = (Projection *) malloc(sizeof(Projection));
+ pj->units = units;
+ pj->proj = proj;
+ }
+ return pj;
+ }
+
+ // Get rid of a projection
+ void delete_Projection(Projection *self) {
+ if(self != NULL) {
+ if(self->proj != NULL)
+ pj_free(self->proj);
+ free(self);
+ }
+ }
+
+ // Do a forward (lat/lon --> world) translation
+ void Projection_Forward(Projection *self, double lat, double lon, double *u, double *v) {
+ projUV latlon, result;
+ latlon.u = lat;
+ latlon.v = lon;
+ if(self->units == DEGREES) {
+ latlon.u *= DEG_TO_RAD;
+ latlon.v *= DEG_TO_RAD;
+ }
+ result = pj_fwd(latlon, self->proj);
+ *u = result.u;
+ *v = result.v;
+ }
+
+ // Do a reverse (world --> lat/lon) translation
+ void Projection_Inverse(Projection *self, double u, double v, double *lat, double *lon) {
+ projUV world, result;
+ world.u = u;
+ world.v = v;
+ result = pj_inv(world, self->proj);
+ if(self->units == DEGREES) {
+ result.u *= RAD_TO_DEG;
+ result.v *= RAD_TO_DEG;
+ }
+ *lat = result.u;
+ *lon = result.v;
+ }
+#ifdef __cplusplus
+extern "C" {
+#endif
+static PyObject *_wrap_int_array(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ int *result ;
+
+ if(!PyArg_ParseTuple(args,"i:int_array",&arg0)) return NULL;
+ result = (int *)int_array(arg0);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_int);
+ {
+ if (!result) {
+ SWIG_exception(SWIG_MemoryError,"Out of memory.");
+ }
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_int_destroy(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:int_destroy",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_int,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ int_destroy(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_int_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:int_get",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_int,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (int )int_get(arg0,arg1);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_int_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int *arg0 ;
+ int arg1 ;
+ int arg2 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"Oii:int_set",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_int,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (int )int_set(arg0,arg1,arg2);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_double_array(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ double *result ;
+
+ if(!PyArg_ParseTuple(args,"i:double_array",&arg0)) return NULL;
+ result = (double *)double_array(arg0);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_double);
+ {
+ if (!result) {
+ SWIG_exception(SWIG_MemoryError,"Out of memory.");
+ }
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_double_destroy(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ double *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:double_destroy",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_double,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ double_destroy(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_double_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ double *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ double result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:double_get",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_double,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (double )double_get(arg0,arg1);
+ resultobj = PyFloat_FromDouble(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_double_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ double *arg0 ;
+ int arg1 ;
+ double arg2 ;
+ PyObject * argo0 =0 ;
+ double result ;
+
+ if(!PyArg_ParseTuple(args,"Oid:double_set",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_double,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (double )double_set(arg0,arg1,arg2);
+ resultobj = PyFloat_FromDouble(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_float_array(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ float *result ;
+
+ if(!PyArg_ParseTuple(args,"i:float_array",&arg0)) return NULL;
+ result = (float *)float_array(arg0);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_float);
+ {
+ if (!result) {
+ SWIG_exception(SWIG_MemoryError,"Out of memory.");
+ }
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_float_destroy(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ float *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:float_destroy",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_float,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ float_destroy(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_float_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ float *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ float result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:float_get",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_float,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (float )float_get(arg0,arg1);
+ resultobj = PyFloat_FromDouble(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_float_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ float *arg0 ;
+ int arg1 ;
+ float arg2 ;
+ PyObject * argo0 =0 ;
+ float result ;
+
+ if(!PyArg_ParseTuple(args,"Oif:float_set",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_float,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (float )float_set(arg0,arg1,arg2);
+ resultobj = PyFloat_FromDouble(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_string_array(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ char **result ;
+
+ if(!PyArg_ParseTuple(args,"i:string_array",&arg0)) return NULL;
+ result = (char **)string_array(arg0);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_p_char);
+ {
+ if (!result) {
+ SWIG_exception(SWIG_MemoryError,"Out of memory.");
+ }
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_string_destroy(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char **arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:string_destroy",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_p_char,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ string_destroy(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_string_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char **arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ char *result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:string_get",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_p_char,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (char *)string_get(arg0,arg1);
+ resultobj = PyString_FromString(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_string_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char **arg0 ;
+ int arg1 ;
+ char *arg2 ;
+ PyObject * argo0 =0 ;
+ char *result ;
+
+ if(!PyArg_ParseTuple(args,"Ois:string_set",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_p_char,1)) == -1) return NULL;
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ result = (char *)string_set(arg0,arg1,arg2);
+ resultobj = PyString_FromString(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_units_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"Oi:Projection_units_set",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ arg0->units = (Units )arg1;
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_units_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"O:Projection_units_get",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ result = (int ) (arg0->units);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_proj_set(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ PJ *arg1 ;
+ PyObject * argo0 =0 ;
+ PyObject * argo1 =0 ;
+
+ if(!PyArg_ParseTuple(args,"OO:Projection_proj_set",&argo0,&argo1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ if ((SWIG_ConvertPtr(argo1,(void **) &arg1,SWIGTYPE_p_PJ,1)) == -1) return NULL;
+ arg0->proj = arg1;
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_proj_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ PyObject * argo0 =0 ;
+ PJ *result ;
+
+ if(!PyArg_ParseTuple(args,"O:Projection_proj_get",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ result = (PJ *) (arg0->proj);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_PJ);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_new_Projection(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char **arg0 ;
+ int arg1 = DEGREES ;
+ PyObject * obj0 = 0 ;
+ Projection *result ;
+
+ if(!PyArg_ParseTuple(args,"O|i:new_Projection",&obj0,&arg1)) return NULL;
+ {
+ /* Check if is a list */
+ if (PyList_Check(obj0)) {
+ int size = PyList_Size(obj0);
+ int i = 0;
+ arg0 = (char **) malloc((size+1)*sizeof(char *));
+ for (i = 0; i < size; i++) {
+ PyObject *o = PyList_GetItem(obj0,i);
+ if (PyString_Check(o))
+ arg0[i] = PyString_AsString(PyList_GetItem(obj0,i));
+ else {
+ PyErr_SetString(PyExc_TypeError,"list must contain strings");
+ free(arg0);
+ return NULL;
+ }
+ }
+ arg0[i] = 0;
+ }else {
+ PyErr_SetString(PyExc_TypeError,"not a list"); return NULL;
+ }
+ }
+ {
+ if (!arg0) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ {
+ /* Use pj_get_errno_ref to access the pj_errno because directly
+ * accessing pj_errno doesn't work on windows if the proj library is
+ * in a DLL */
+ *pj_get_errno_ref() = 0;
+ result = (Projection *)new_Projection(arg0,(Units )arg1);
+;
+ if (!result)
+ {
+ /* FIXME: There's a case where result is NULL and pj_errno is
+ * not set, namely when memory allocation of the Projection
+ * struct fails. */
+ SWIG_exception(SWIG_IOError, pj_strerrno(*pj_get_errno_ref()));
+ }
+}resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Projection);
+{
+ free((char *) arg0);
+}
+return resultobj;
+}
+
+
+static PyObject *_wrap_delete_Projection(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:delete_Projection",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ delete_Projection(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_Forward(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ double arg1 ;
+ double arg2 ;
+ double *arg3 ;
+ double *arg4 ;
+ double temp ;
+ double temp0 ;
+ PyObject * argo0 =0 ;
+
+ {
+ arg3 = &temp;
+ }
+ {
+ arg4 = &temp0;
+ }
+ if(!PyArg_ParseTuple(args,"Odd:Projection_Forward",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ {
+ if (!arg3) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ {
+ if (!arg4) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ Projection_Forward(arg0,arg1,arg2,arg3,arg4);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ {
+ PyObject *o;
+ o = PyFloat_FromDouble(*arg3);
+ if ((!resultobj) || (resultobj == Py_None)) {
+ resultobj = o;
+ }else {
+ if (!PyList_Check(resultobj)) {
+ PyObject *o2 = resultobj;
+ resultobj = PyList_New(0);
+ PyList_Append(resultobj,o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(resultobj,o);
+ Py_XDECREF(o);
+ }
+ }
+ {
+ PyObject *o;
+ o = PyFloat_FromDouble(*arg4);
+ if ((!resultobj) || (resultobj == Py_None)) {
+ resultobj = o;
+ }else {
+ if (!PyList_Check(resultobj)) {
+ PyObject *o2 = resultobj;
+ resultobj = PyList_New(0);
+ PyList_Append(resultobj,o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(resultobj,o);
+ Py_XDECREF(o);
+ }
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_Projection_Inverse(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ double arg1 ;
+ double arg2 ;
+ double *arg3 ;
+ double *arg4 ;
+ double temp ;
+ double temp0 ;
+ PyObject * argo0 =0 ;
+
+ {
+ arg3 = &temp;
+ }
+ {
+ arg4 = &temp0;
+ }
+ if(!PyArg_ParseTuple(args,"Odd:Projection_Inverse",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ {
+ if (!arg3) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ {
+ if (!arg4) {
+ SWIG_exception(SWIG_ValueError,"Received a NULL Pointer");
+ }
+ }
+ Projection_Inverse(arg0,arg1,arg2,arg3,arg4);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ {
+ PyObject *o;
+ o = PyFloat_FromDouble(*arg3);
+ if ((!resultobj) || (resultobj == Py_None)) {
+ resultobj = o;
+ }else {
+ if (!PyList_Check(resultobj)) {
+ PyObject *o2 = resultobj;
+ resultobj = PyList_New(0);
+ PyList_Append(resultobj,o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(resultobj,o);
+ Py_XDECREF(o);
+ }
+ }
+ {
+ PyObject *o;
+ o = PyFloat_FromDouble(*arg4);
+ if ((!resultobj) || (resultobj == Py_None)) {
+ resultobj = o;
+ }else {
+ if (!PyList_Check(resultobj)) {
+ PyObject *o2 = resultobj;
+ resultobj = PyList_New(0);
+ PyList_Append(resultobj,o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(resultobj,o);
+ Py_XDECREF(o);
+ }
+ }
+ return resultobj;
+}
+
+
+PyObject * Projection_cobject(Projection *self) {
+ {
+ return PyCObject_FromVoidPtr(self->proj, NULL);
+ }
+}
+
+
+static PyObject *_wrap_Projection_cobject(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ Projection *arg0 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"O:Projection_cobject",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_Projection,1)) == -1) return NULL;
+ result = (PyObject *)Projection_cobject(arg0);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+static PyMethodDef ProjectioncMethods[] = {
+ { "int_array", _wrap_int_array, METH_VARARGS },
+ { "int_destroy", _wrap_int_destroy, METH_VARARGS },
+ { "int_get", _wrap_int_get, METH_VARARGS },
+ { "int_set", _wrap_int_set, METH_VARARGS },
+ { "double_array", _wrap_double_array, METH_VARARGS },
+ { "double_destroy", _wrap_double_destroy, METH_VARARGS },
+ { "double_get", _wrap_double_get, METH_VARARGS },
+ { "double_set", _wrap_double_set, METH_VARARGS },
+ { "float_array", _wrap_float_array, METH_VARARGS },
+ { "float_destroy", _wrap_float_destroy, METH_VARARGS },
+ { "float_get", _wrap_float_get, METH_VARARGS },
+ { "float_set", _wrap_float_set, METH_VARARGS },
+ { "string_array", _wrap_string_array, METH_VARARGS },
+ { "string_destroy", _wrap_string_destroy, METH_VARARGS },
+ { "string_get", _wrap_string_get, METH_VARARGS },
+ { "string_set", _wrap_string_set, METH_VARARGS },
+ { "Projection_units_set", _wrap_Projection_units_set, METH_VARARGS },
+ { "Projection_units_get", _wrap_Projection_units_get, METH_VARARGS },
+ { "Projection_proj_set", _wrap_Projection_proj_set, METH_VARARGS },
+ { "Projection_proj_get", _wrap_Projection_proj_get, METH_VARARGS },
+ { "new_Projection", _wrap_new_Projection, METH_VARARGS },
+ { "delete_Projection", _wrap_delete_Projection, METH_VARARGS },
+ { "Projection_Forward", _wrap_Projection_Forward, METH_VARARGS },
+ { "Projection_Inverse", _wrap_Projection_Inverse, METH_VARARGS },
+ { "Projection_cobject", _wrap_Projection_cobject, METH_VARARGS },
+ { NULL, NULL }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_float[] = {{"_p_float", 0, "float *"},{"_p_float"},{0}};
+static swig_type_info _swigt__p_double[] = {{"_p_double", 0, "double *"},{"_p_double"},{0}};
+static swig_type_info _swigt__p_p_char[] = {{"_p_p_char", 0, "char **"},{"_p_p_char"},{0}};
+static swig_type_info _swigt__p_PJ[] = {{"_p_PJ", 0, "PJ *"},{"_p_PJ"},{0}};
+static swig_type_info _swigt__p_int[] = {{"_p_int", 0, "int *"},{"_p_int"},{0}};
+static swig_type_info _swigt__p_Projection[] = {{"_p_Projection", 0, "Projection *"},{"_p_Projection"},{0}};
+
+static swig_type_info *swig_types_initial[] = {
+_swigt__p_float,
+_swigt__p_double,
+_swigt__p_p_char,
+_swigt__p_PJ,
+_swigt__p_int,
+_swigt__p_Projection,
+0
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+ { SWIG_PY_INT, "DEGREES", (long) DEGREES, 0, 0, 0},
+ { SWIG_PY_INT, "RADIANS", (long) RADIANS, 0, 0, 0},
+{0}};
+
+static PyObject *SWIG_globals;
+#ifdef __cplusplus
+extern "C"
+#endif
+SWIGEXPORT(void) initProjectionc(void) {
+ PyObject *m, *d;
+ int i;
+ SWIG_globals = SWIG_newvarlink();
+ m = Py_InitModule("Projectionc", ProjectioncMethods);
+ d = PyModule_GetDict(m);
+ for (i = 0; swig_types_initial[i]; i++) {
+ swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);
+ }
+ SWIG_InstallConstants(d,swig_const_table);
+}
+
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/setup.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/setup.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/setup.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,22 @@
+
+import os, os.path
+from distutils.core import setup, Extension
+
+PROJ4_PREFIX = "/"
+PROJ4_INCLUDE = os.path.join(PROJ4_PREFIX, "usr/local/include")
+PROJ4_LIB = os.path.join(PROJ4_PREFIX, "usr/local/lib")
+
+extensions = [Extension("Projectionc",
+ ["Projection_wrap.c"],
+ include_dirs = [PROJ4_INCLUDE],
+ library_dirs = [PROJ4_LIB],
+ libraries = ["proj"])]
+
+setup(name = "py-Projection",
+ version = "0.1",
+ description = "Python bindings for PROJ.4",
+ author = "Douglas K. Rand",
+ author_email = "rand at meridian-enviro.com",
+ py_modules = ["Projection"],
+ ext_modules = extensions)
+
Added: packages/thuban/branches/upstream/current/libraries/pyprojection/swighelp.txt
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyprojection/swighelp.txt 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyprojection/swighelp.txt 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,7 @@
+swig1.1 -python -shadow Projection.i
+
+gcc -fpic -c Projection_wrap.c -I/usr/local/include/python1.5 -I/home/Agena/jeinhorn/project/proj4-pythonbindings/src
+
+
+gcc -shared Projection_wrap.o -o Projectionmodule.so -L/usr/local/lib -lproj
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/COPYING
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/COPYING 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/COPYING 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/ChangeLog
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/ChangeLog 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/ChangeLog 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,207 @@
+2006-09-24 Bernhard Reiter <bernhard at intevation.de>
+
+ * dbflib_wrap.c, README: Checked for python version >= 2.4.0a0
+ before using &PyOS_ascii_atof.
+
+2006-09-24 Bernhard Reiter <bernhard at intevation.de>
+
+ Added dirty workaround to make dbflib agnostic
+ against decimal_poinst != ".\0".
+
+ * dbflib_wrap.c: Added call DBFSetatof_function(&PyOS_ascii_atof);
+ to initdbflibc().
+ * README: noted that manual editing of dbflib_wrap.c is necessary now.
+
+2005-06-30 Bernhard Herzog <bh at intevation.de>
+
+ * shapelib.i (new_SHPObject): Fix the test for the length of the
+ part types. It used the wrong variable.
+
+ * shapelib_wrap.c: Regenerated from shapelib.i
+
+ * pytest.py (make_shapefile): Add some more comments and add an
+ example with a polygon with a hole.
+
+2004-12-27 Bernhard Reiter <bernhard at intevation.de>
+
+ * README: Refering to the new homepage shapelib.maptools.org now.
+
+2004-12-13 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.py: Updated from difflib.i with SWIG.
+
+ * dbflib.i: Work around a bug in the generated python code which
+ leads to exception in the __del__ method when the constructor
+ fails. See the comments in the code for more details.
+
+2004-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * README: Flesh out the some more. Correct the shapelib
+ requirements.
+
+ * NEWS: Update the date of the actual release of 0.3
+
+2004-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * setup.py: Determine shp_dir correctly when run with bdist_rpm
+ (dbf_macros): Remove a debug print
+
+ * NEWS: Also mention the new (compared to 0.2) setup.py
+
+ * MANIFEST.in: New. Define which files belong into a source
+ distribution
+
+2004-05-17 Bernhard Herzog <bh at intevation.de>
+
+ * README: Update for new release
+
+ * setup.py (dbf_macros): New. Return the preprocessor macros
+ needed to compile the dbflib wrapper. Determine whether
+ DBFUpdateHeader is available and define the right value of
+ HAVE_UPDATE_HEADER
+ (extensions): Use dbf_macros for the dbflibc extension
+
+ * dbflib_wrap.c, dbflib.py: Update from dbflib.i
+
+ * dbflib.i (DBFInfo_commit): New. Implementation of the commit
+ method. This new indirection is necessary because we use the
+ DBFUpdateHeader function now which is not available in shapelib <=
+ 1.2.10
+ (DBFFile::commit): Use DBFInfo_commit as implementation
+ (pragma __class__): New. Kludge to remove the commit method when
+ the DBFUpdateHeader function isn't available
+ (_have_commit): New. Helper for the pragma kludge.
+
+2003-11-03 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i (do_read_attribute): New helper function for reading
+ one attribute as a python object
+ (DBFInfo_read_attribute): New. Implement the read_attribute method
+ (DBFInfo_read_record): Use do_read_attribute to read the
+ individual values
+ (struct DBFFile): Add the read_attribute method.
+
+ * dbflib_wrap.c, dbflib.py: Update from dbflib.i.
+
+2003-09-29 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i: Add exception typemap for the add_field method. Fixes
+ Thuban bug RT#1842
+
+ * dbflib_wrap.c: Update from dbflib.i
+
+ * testdbf.py: New. Test cases for the dbflib bindings based on the
+ unittest module
+
+2003-08-18 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i (DBFInfo_write_record): Use PySequence_Check instead of
+ PyMapping_Check to distinguish between sequences and mappings
+ because in Python 2.3, PyMapping_Check returns true for tuples and
+ lists too.
+
+2003-05-28 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i (DBFInfo_read_record): Read NULL fields as None unless
+ it's a string field. DBF files can't distinguish between NULL and
+ an empty string. Also, check the return value of
+ DBFReadStringAttribute which may return NULL to indicate errors.
+
+ * dbflib_wrap.c: Updated from dbflib.i
+
+2002-08-27 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i: Raise an exception if open or create fails.
+
+ * shapelib.i: Slightly better wording for the IOError exception
+ that open and create may raise.
+
+ * shapelib_wrap.c, dbflib_wrap.c: Regenerated
+
+2002-08-22 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i (DBFFile::commit): New method for DBFCommit.
+
+ * dbflib_wrap.c, dbflib.py: Update from dbflib.i
+
+2002-08-15 Bernhard Herzog <bh at intevation.de>
+
+ * shapelib.i, dbflib.i: Make the NOCHECK trick for the ShapeFile *
+ check typemap work with SWIG 1.3.
+
+ * shapelib_wrap.c, dbflib_wrap.c: Regenerate from the .i files.
+
+2002-05-10 Bernhard Herzog <bh at intevation.de>
+
+ * dbflib.i (DBFInfo_write_record): Only DECREF if the return value
+ of PyMapping_GetItemString is not NULL. Also, test the return
+ value of PySequence_GetItem
+ (write_field): Remove some debug prints
+
+ * dbflib_wrap.c: Updated from dbflib.i
+
+2002-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * shptreemodule.c (SHPTreeType, initshptree): Set SHPTreeType's
+ PyType_Type pointer in the init function.
+ (shptree_methods): Use METH_VARARGS
+ (shptree_dealloc): Use PyMem_DEL
+ (shptree_find_shapes): Add a missing return
+
+2002-05-07 Bernhard Herzog <bh at intevation.de>
+
+ * shptreemodule.c: New file with a simple wrapper for shapelib's
+ quadtree
+
+ * setup.py: Some fixes to use explicit forward slashes as
+ directory separators because of distutils.
+ (extensions): Add the shptree module.
+
+ * pytest.py (read_shapefile): Add some demo calls for the shptree
+ module
+
+ * pyshapelib_api.h (PyShapeLibAPI): Add some of the shptree
+ functions.
+ (PYSHAPELIB_IMPORT_API): New macro to import the API
+
+ * shapelib.i (the_api): add the tree API functions.
+
+ * shapelib_wrap.c: Updated from shapelib.i with SWIG.
+
+2002-04-11 Bernhard Herzog <bh at intevation.de>
+
+ * pyshapelib_api.h: New file with a limited C-level API for
+ accessing shapilib functions from other Python-extensions.
+
+ * shapelib.i: Export the C-level API with the c_api function.
+
+ * shapelib.py, shapelib_wrap.c: Updated from shapelib.i. Still
+ done with a very old version of SWIG, but it's probably not worth
+ it to try it with a newer version as long as this still works.
+
+2001-07-18 Bernhard Herzog <bh at intevation.de>
+
+ * shapelib.i (open_ShapeFile): declare the swig prototype
+ correctly with ShapeFile* as return type
+ (ShapeFile.cobject): New method returning the SHPHandle* as a
+ CObject
+
+ * Makefile (VERSION): Increase to 0.3
+
+ * setup.py, MANIFEST.in: New files for python distutils.
+
+2001-06-15 Bernhard Herzog <bh at intevation.de>
+
+ * Makefile (VERSION): Increase to 0.2
+
+2001-06-14 Bernhard Herzog <bh at intevation.de>
+
+ * shapelib.i: Add the functions SHPTypeName as type_name and
+ SHPPartTypeName as part_type_name
+ (SHPObject_vertices):
+ (build_vertex_list): Put building a list of vertices into the
+ separate function build_vertex_list so that SHPObject_vertices can
+ support SHPT_POINT too.
+
+ * ChangeLog: create ChangeLog
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/MANIFEST.in
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/MANIFEST.in 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/MANIFEST.in 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,8 @@
+include README COPYING ChangeLog NEWS
+include *.i *.c *.py *.h
+include MANIFEST.in
+
+# prune the references to the shapelib files which are in either .. or
+# ../shapelib. These are pulled in by distutils because they're
+# referenced by the Extension objects
+prune ..
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/NEWS
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/NEWS 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/NEWS 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,43 @@
+pyshapelib 0.3 (2004-05-28)
+===========================
+
+ * New module shptree. It's a simple wrapper for shapelib's quadtree.
+
+ * Provide a way to access the shapelib module and shapefile objects
+ from C. It's not documented, unfortunately, but pyshapelib_api.h may
+ be a starting point. This feature is used in Thuban which could be
+ used as an example.
+
+ * distutils based build and install script, setup.py
+
+Module dbflib:
+
+ * dbf objects now have a method commit if compiled with shapelib newer
+ than 1.2.10 (that is only the CVS version of shapelib at the time of
+ writing). This method calls the new function dbflib DBFUpdateHeader.
+
+ * New method read_attribute which reads a single attribute instead of a
+ whole record like read_record
+
+ * NULL values are now returned as None. DBF files don't really support
+ NULL, but this change matches a new feature in shapelib 1.2.9. It's
+ not clear whether it should be implemented in the python wrapper in
+ this way. It might be better to make it optional.
+
+
+pyshapelib 0.2 (2001-06-15)
+===========================
+
+Module shapelib:
+
+ * new module level functions type_name and part_type_name
+ (corresponding to SHPTypeName and SHPPartTypeName)
+
+ * The vertices() method of shape objects works for shape type
+ SHPT_POINT, too.
+
+
+pyshapelib 0.1 (2000-12-20)
+===========================
+
+Initial public release
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/README
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,105 @@
+
+Python bindings for Shapelib
+============================
+
+These are three python modules for shapelib:
+
+ shapelib read/write shapefiles
+
+ dbflib read/write dbf files
+
+ shptree quadtree for shapes
+
+Shapelib is a free software library for reading and writing ESRI shape
+files and can be found at http://shapelib.maptools.org/.
+
+The bindings were partly created with SWIG, a tool that can generate
+wrappers of C and C++ libraries for a variety of scripting languages.
+It's homepage is http://www.swig.org.
+
+The bindings themselves don't have a homepage at the moment, but the
+source tarballs/zip files can be downloaded from
+http://ftp.intevation.de/users/bh/pyshapelib/
+
+
+Requirements
+------------
+
+To compile the bindings, you need shapelib 1.2.9 or newer and Python 2.0
+or newer.
+
+SWIG is not required. The files generated by SWIG are contained in the
+archive. If you modify shapelib.i or dbflib.i and need to recreate the
+generated files, you need SWIG 1.3 Alpha 5. It's unlikely that other
+versions will work.
+In addition you need to add the following lines to initdbflibc(void)
+in dbflib_wrap.c.
+ /* because we are in a python module now, we can give out
+ * pointers to python's locale agonistic function
+ * XXX this clearly is a hack
+ */
+ DBFSetatof_function(&PyOS_ascii_atof);
+
+You also need Python, of course. If you installed prebuilt packages
+such as RPMs of some Linux distributions, please make sure that the
+development package is also installed.
+
+
+License
+-------
+
+The shapelib python bindings are covered by the LGPL. See COPYING for
+more information.
+
+
+Compilation and Installation
+----------------------------
+
+Pyshapelib uses the python distutils which come with Python 2.0 or newer
+and are also available separately from python.org for older versions.
+
+To compile the bindings, unpack the archive under the shapelib archive
+or move the directory there if you've already unpacked it. The setup
+script expects to find the shapelib files in the parent directory. Then
+run
+
+ python setup.py build
+
+to build the bindings. The result can be found under the (new) build
+subirectory.
+
+To install run
+
+ python setup.py install
+
+which will install the bindings into python's site-packages directory.
+You can use the intall command's --prefix option to select a different
+installatin directory.
+
+For more information about the setup.py script, invoke it with the
+--help option:
+
+ python setup.py --help
+
+
+Documentation
+-------------
+
+There's no real documentation for the python bindings themselves, but
+there's a simple demo/test script called pytest.py.
+
+The change history is recorded in NEWS and in detail in ChangeLog.
+
+
+Contact Information
+-------------------
+
+pyshapelib is currently being developed as part of the interactive
+viewer for geographic data Thuban, so the best way to reach the
+developers is to post on the Thuban mailing lists.
+
+Thuban:
+ http://thuban.intevation.org/
+
+Thuban mailing lists:
+ http://thuban.intevation.org/mailinglist.html
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.i
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.i 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.i 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,597 @@
+/* SWIG (www.swig.org) interface file for the dbf interface of shapelib
+ *
+ * At the moment (Dec 2000) this file is only useful to generate Python
+ * bindings. Invoke swig as follows:
+ *
+ * swig -python -shadow dbflib.i
+ *
+ * to generate dbflib_wrap.c and dbflib.py. dbflib_wrap.c defines a
+ * bunch of Python-functions that wrap the appripriate dbflib functions
+ * and dbflib.py contains an object oriented wrapper around
+ * dbflib_wrap.c.
+ *
+ * This module defines one object type: DBFFile.
+ */
+
+/* this is the dbflib module */
+%module dbflib
+
+/* first a %{,%} block. These blocks are copied verbatim to the
+ * dbflib_wrap.c file and are not parsed by SWIG. This is the place to
+ * import headerfiles and define helper-functions that are needed by the
+ * automatically generated wrappers.
+ */
+
+%{
+#include "shapefil.h"
+
+
+/* Read one attribute from the dbf handle and return it as a new python object
+ *
+ * If an error occurs, set the appropriate Python exception and return
+ * NULL.
+ *
+ * Assume that the values of the record and field arguments are valid.
+ * The name argument will be passed to DBFGetFieldInfo as is and should
+ * thus be either NULL or a pointer to an array of at least 12 chars
+ */
+static PyObject *
+do_read_attribute(DBFInfo * handle, int record, int field, char * name)
+{
+ int type, width;
+ PyObject *value;
+
+ type = DBFGetFieldInfo(handle, field, name, &width, NULL);
+ /* For strings NULL and the empty string are indistinguishable
+ * in DBF files. We prefer empty strings instead for backwards
+ * compatibility reasons because older wrapper versions returned
+ * emtpy strings as empty strings.
+ */
+ if (type != FTString && DBFIsAttributeNULL(handle, record, field))
+ {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+ else
+ {
+ switch (type)
+ {
+ case FTString:
+ {
+ const char * temp = DBFReadStringAttribute(handle, record, field);
+ if (temp)
+ {
+ value = PyString_FromString(temp);
+ }
+ else
+ {
+ PyErr_Format(PyExc_IOError,
+ "Can't read value for row %d column %d",
+ record, field);
+ value = NULL;
+ }
+ break;
+ }
+ case FTInteger:
+ value = PyInt_FromLong(DBFReadIntegerAttribute(handle, record,
+ field));
+ break;
+ case FTDouble:
+ value = PyFloat_FromDouble(DBFReadDoubleAttribute(handle, record,
+ field));
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError, "Invalid field data type %d",
+ type);
+ value = NULL;
+ }
+ }
+ if (!value)
+ return NULL;
+
+ return value;
+}
+
+/* the read_attribute method. Return the value of the given record and
+ * field as a python object of the appropriate type.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ */
+
+static PyObject *
+DBFInfo_read_attribute(DBFInfo * handle, int record, int field)
+{
+ if (record < 0 || record >= DBFGetRecordCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "record index %d out of bounds (record count: %d)",
+ record, DBFGetRecordCount(handle));
+ return NULL;
+ }
+
+ if (field < 0 || field >= DBFGetFieldCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "field index %d out of bounds (field count: %d)",
+ field, DBFGetFieldCount(handle));
+ return NULL;
+ }
+
+ return do_read_attribute(handle, record, field, NULL);
+}
+
+
+/* the read_record method. Return the record record as a dictionary with
+ * whose keys are the names of the fields, and their values as the
+ * appropriate Python type.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ */
+
+static PyObject *
+DBFInfo_read_record(DBFInfo * handle, int record)
+{
+ int num_fields;
+ int i;
+ int type, width;
+ char name[12];
+ PyObject *dict;
+ PyObject *value;
+
+ if (record < 0 || record >= DBFGetRecordCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "record index %d out of bounds (record count: %d)",
+ record, DBFGetRecordCount(handle));
+ return NULL;
+ }
+
+ dict = PyDict_New();
+ if (!dict)
+ return NULL;
+
+ num_fields = DBFGetFieldCount(handle);
+ for (i = 0; i < num_fields; i++)
+ {
+ value = do_read_attribute(handle, record, i, name);
+ if (!value)
+ goto fail;
+
+ PyDict_SetItemString(dict, name, value);
+ Py_DECREF(value);
+ }
+
+ return dict;
+
+ fail:
+ Py_XDECREF(dict);
+ return NULL;
+}
+
+/* the write_record method. Write the record record given wither as a
+ * dictionary or a sequence (i.e. a list or a tuple).
+ *
+ * If it's a dictionary the keys must be the names of the fields and
+ * their value must have a suitable type. Only the fields actually
+ * contained in the dictionary are written. Fields for which there's no
+ * item in the dict are not modified.
+ *
+ * If it's a sequence, all fields must be present in the right order.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ *
+ * The method is implemented with two c-functions, write_field to write
+ * a single field and DBFInfo_write_record as the front-end.
+ */
+
+
+/* write a single field of a record. */
+static int
+write_field(DBFHandle handle, int record, int field, int type,
+ PyObject * value)
+{
+ char * string_value;
+ int int_value;
+ double double_value;
+
+ if (value == Py_None)
+ {
+ if (!DBFWriteNULLAttribute(handle, record, field))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write NULL field %d of record %d",
+ field, record);
+ return 0;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case FTString:
+ string_value = PyString_AsString(value);
+ if (!string_value)
+ return 0;
+ if (!DBFWriteStringAttribute(handle, record, field, string_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ case FTInteger:
+ int_value = PyInt_AsLong(value);
+ if (int_value == -1 && PyErr_Occurred())
+ return 0;
+ if (!DBFWriteIntegerAttribute(handle, record, field, int_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ case FTDouble:
+ double_value = PyFloat_AsDouble(value);
+ if (double_value == -1 && PyErr_Occurred())
+ return 0;
+ if (!DBFWriteDoubleAttribute(handle, record, field, double_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static
+PyObject *
+DBFInfo_write_record(DBFHandle handle, int record, PyObject *record_object)
+{
+ int num_fields;
+ int i, length;
+ int type, width;
+ char name[12];
+ PyObject * value = NULL;
+
+ num_fields = DBFGetFieldCount(handle);
+
+ /* We used to use PyMapping_Check to test whether record_object is a
+ * dictionary like object instead of PySequence_Check to test
+ * whether it's a sequence. Unfortunately in Python 2.3
+ * PyMapping_Check returns true for lists and tuples too so the old
+ * approach doesn't work anymore.
+ */
+ if (PySequence_Check(record_object))
+ {
+ /* It's a sequence object. Iterate through all items in the
+ * sequence and write them to the appropriate field.
+ */
+ length = PySequence_Length(record_object);
+ if (length != num_fields)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "record must have one item for each field");
+ goto fail;
+ }
+ for (i = 0; i < length; i++)
+ {
+ type = DBFGetFieldInfo(handle, i, name, &width, NULL);
+ value = PySequence_GetItem(record_object, i);
+ if (value)
+ {
+ if (!write_field(handle, record, i, type, value))
+ goto fail;
+ Py_DECREF(value);
+ }
+ else
+ {
+ goto fail;
+ }
+ }
+ }
+ else
+ {
+ /* It's a dictionary-like object. Iterate over the names of the
+ * known fields and write the corresponding item
+ */
+ for (i = 0; i < num_fields; i++)
+ {
+ type = DBFGetFieldInfo(handle, i, name, &width, NULL);
+
+ /* if the dictionary has the key name write that object to
+ * the appropriate field, other wise just clear the python
+ * exception and do nothing.
+ */
+ value = PyMapping_GetItemString(record_object, name);
+ if (value)
+ {
+ if (!write_field(handle, record, i, type, value))
+ goto fail;
+ Py_DECREF(value);
+ }
+ else
+ {
+ PyErr_Clear();
+ }
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ fail:
+ Py_XDECREF(value);
+ return NULL;
+}
+%}
+
+
+/* The commit method implementation
+ *
+ * The method relies on the DBFUpdateHeader method which is not
+ * available in shapelib <= 1.2.10. setup.py defines
+ * HAVE_UPDATE_HEADER's value depending on whether the function is
+ * available in the shapelib version the code is compiled with.
+ */
+%{
+static
+void
+DBFInfo_commit(DBFHandle handle)
+{
+#if HAVE_UPDATE_HEADER
+ DBFUpdateHeader(handle);
+#endif
+}
+%}
+
+
+/*
+ * The SWIG Interface definition.
+ */
+
+/* include some common SWIG type definitions and standard exception
+ handling code */
+%include typemaps.i
+%include exception.i
+
+/* As for ShapeFile in shapelib.i, We define a new C-struct that holds
+ * the DBFHandle. This is mainly done so we can separate the close()
+ * method from the destructor but it also helps with exception handling.
+ *
+ * After the DBFFile has been opened or created the handle is not NULL.
+ * The close() method closes the file and sets handle to NULL as an
+ * indicator that the file has been closed.
+ */
+
+%{
+ typedef struct {
+ DBFHandle handle;
+ } DBFFile;
+%}
+
+
+/* The first argument to the DBFFile methods is a DBFFile pointer.
+ * We have to check whether handle is not NULL in most methods but not
+ * all. In the destructor and the close method, it's OK for handle to be
+ * NULL. We achieve this by checking whether the preprocessor macro
+ * NOCHECK_$name is defined. SWIG replaces $name with the name of the
+ * function for which the code is inserted. In the %{,%}-block below we
+ * define the macros for the destructor and the close() method.
+ */
+
+%typemap(python,check) DBFFile *{
+%#ifndef NOCHECK_$name
+ if (!$target || !$target->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+%#endif
+}
+
+%{
+#define NOCHECK_delete_DBFFile
+#define NOCHECK_DBFFile_close
+%}
+
+
+/* An exception handle for the constructor and the module level open()
+ * and create() functions.
+ *
+ * Annoyingly, we *have* to put braces around the SWIG_exception()
+ * calls, at least in the python case, because of the way the macro is
+ * written. Of course, always putting braces around the branches of an
+ * if-statement is often considered good practice.
+ */
+%typemap(python,except) DBFFile * {
+ $function;
+ if (!$source)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!$source->handle)
+ {
+ SWIG_exception(SWIG_IOError, "$name failed");
+ }
+}
+
+/* Exception handler for the add_field method */
+%typemap(python,except) int DBFFile_add_field {
+ $function;
+ if ($source < 0)
+ {
+ SWIG_exception(SWIG_RuntimeError, "add_field failed");
+ }
+}
+
+/* define and use some typemaps for the field_info() method whose
+ * C-implementation has three output parameters that are returned
+ * through pointers passed into the function. SWIG already has
+ * definitions for common types such as int* and we can use those for
+ * the last two parameters:
+ */
+
+%apply int * OUTPUT { int * output_width }
+%apply int * OUTPUT { int * output_decimals }
+
+/* the fieldname has to be defined manually: */
+%typemap(python,ignore) char *fieldname_out(char temp[12]) {
+ $target = temp;
+}
+
+%typemap(python,argout) char *fieldname_out() {
+ PyObject * string = PyString_FromString($source);
+ $target = t_output_helper($target,string);
+}
+
+
+
+/*
+ * The SWIG-version of the DBFFile struct
+ */
+
+typedef struct
+{
+ %addmethods {
+ DBFFile(const char *file, const char * mode = "rb") {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFOpen(file, mode);
+ return self;
+ }
+
+ ~DBFFile() {
+ if (self->handle)
+ DBFClose(self->handle);
+ free(self);
+ }
+
+ void close() {
+ if (self->handle)
+ DBFClose(self->handle);
+ self->handle = NULL;
+ }
+
+ int field_count() {
+ return DBFGetFieldCount(self->handle);
+ }
+
+ int record_count() {
+ return DBFGetRecordCount(self->handle);
+ }
+
+ int field_info(int iField, char * fieldname_out,
+ int * output_width, int * output_decimals) {
+ return DBFGetFieldInfo(self->handle, iField, fieldname_out,
+ output_width, output_decimals);
+ }
+
+ PyObject * read_record(int record) {
+ return DBFInfo_read_record(self->handle, record);
+ }
+
+ PyObject * read_attribute(int record, int field) {
+ return DBFInfo_read_attribute(self->handle, record, field);
+ }
+
+ int add_field(const char * pszFieldName, DBFFieldType eType,
+ int nWidth, int nDecimals) {
+ return DBFAddField(self->handle, pszFieldName, eType, nWidth,
+ nDecimals);
+ }
+
+ PyObject *write_record(int record, PyObject *dict_or_sequence) {
+ return DBFInfo_write_record(self->handle, record,
+ dict_or_sequence);
+ }
+
+ void commit() {
+ DBFInfo_commit(self->handle);
+ }
+ /* Delete the commit method from the class if it doesn't have a
+ * real implementation.
+ */
+ %pragma(python) addtomethod="__class__:if not dbflibc._have_commit: del commit"
+
+ /* The __del__ method generated by the old SWIG version we're
+ * tries to access self.thisown which may not be set at all when
+ * there was an exception during construction. Therefore we
+ * override it with our own version.
+ * FIXME: It would be better to upgrade to a newer SWIG version
+ * or to get rid of SWIG entirely.
+ */
+ %pragma(python) addtoclass = "
+ def __del__(self,dbflibc=dbflibc):
+ if getattr(self, 'thisown', 0):
+ dbflibc.delete_DBFFile(self)
+ "
+
+
+ }
+} DBFFile;
+
+
+/*
+ * Two module level functions, open() and create() that correspond to
+ * DBFOpen and DBFCreate respectively. open() is equivalent to the
+ * DBFFile constructor.
+ */
+
+
+%{
+ DBFFile * open_DBFFile(const char * file, const char * mode)
+ {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFOpen(file, mode);
+ return self;
+ }
+%}
+
+%name(open) %new DBFFile * open_DBFFile(const char * file,
+ const char * mode = "rb");
+
+%{
+ DBFFile * create_DBFFile(const char * file)
+ {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFCreate(file);
+ return self;
+ }
+%}
+%name(create) %new DBFFile * create_DBFFile(const char * file);
+
+
+
+/* constant definitions copied from shapefil.h */
+typedef enum {
+ FTString,
+ FTInteger,
+ FTDouble,
+ FTInvalid
+} DBFFieldType;
+
+
+/* Put the value of the HAVE_UPDATE_HEADER preprocessor macro into the
+ * wrapper so that the __class__ pragma above knows when to remove the
+ * commit method
+ */
+const int _have_commit = HAVE_UPDATE_HEADER;
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,76 @@
+# This file was created automatically by SWIG.
+import dbflibc
+class DBFFile:
+ def __init__(self,*args):
+ self.this = apply(dbflibc.new_DBFFile,args)
+ self.thisown = 1
+
+ def __del__(self,dbflibc=dbflibc):
+ if self.thisown == 1 :
+ dbflibc.delete_DBFFile(self)
+ def close(*args):
+ val = apply(dbflibc.DBFFile_close,args)
+ return val
+ def field_count(*args):
+ val = apply(dbflibc.DBFFile_field_count,args)
+ return val
+ def record_count(*args):
+ val = apply(dbflibc.DBFFile_record_count,args)
+ return val
+ def field_info(*args):
+ val = apply(dbflibc.DBFFile_field_info,args)
+ return val
+ def read_record(*args):
+ val = apply(dbflibc.DBFFile_read_record,args)
+ return val
+ def read_attribute(*args):
+ val = apply(dbflibc.DBFFile_read_attribute,args)
+ return val
+ def add_field(*args):
+ val = apply(dbflibc.DBFFile_add_field,args)
+ return val
+ def write_record(*args):
+ val = apply(dbflibc.DBFFile_write_record,args)
+ return val
+ def commit(*args):
+ val = apply(dbflibc.DBFFile_commit,args)
+ return val
+ def __repr__(self):
+ return "<C DBFFile instance at %s>" % (self.this,)
+ if not dbflibc._have_commit: del commit
+
+ def __del__(self,dbflibc=dbflibc):
+ if getattr(self, 'thisown', 0):
+ dbflibc.delete_DBFFile(self)
+
+class DBFFilePtr(DBFFile):
+ def __init__(self,this):
+ self.this = this
+ self.thisown = 0
+ self.__class__ = DBFFile
+
+
+
+
+
+#-------------- FUNCTION WRAPPERS ------------------
+
+def open(*args, **kwargs):
+ val = apply(dbflibc.open,args,kwargs)
+ if val: val = DBFFilePtr(val); val.thisown = 1
+ return val
+
+def create(*args, **kwargs):
+ val = apply(dbflibc.create,args,kwargs)
+ if val: val = DBFFilePtr(val); val.thisown = 1
+ return val
+
+
+
+#-------------- VARIABLE WRAPPERS ------------------
+
+FTString = dbflibc.FTString
+FTInteger = dbflibc.FTInteger
+FTDouble = dbflibc.FTDouble
+FTInvalid = dbflibc.FTInvalid
+_have_commit = dbflibc._have_commit
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib_wrap.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib_wrap.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/dbflib_wrap.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1431 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3u-20020503-1857 (Alpha 5)
+ * And later MANUALLY edited at the end.
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPYTHON
+/***********************************************************************
+ * common.swg
+ *
+ * This file contains generic SWIG runtime support for pointer
+ * type checking as well as a few commonly used macros to control
+ * external linkage.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ *
+ * Copyright (c) 1999-2000, The University of Chicago
+ *
+ * This file may be freely redistributed without license or fee provided
+ * this copyright message remains intact.
+ ************************************************************************/
+
+#include <string.h>
+
+#if defined(_WIN32) || defined(__WIN32__)
+# if defined(_MSC_VER)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT(a) a
+# else
+# define SWIGEXPORT(a) __declspec(dllexport) a
+# endif
+# else
+# if defined(__BORLANDC__)
+# define SWIGEXPORT(a) a _export
+# else
+# define SWIGEXPORT(a) a
+# endif
+#endif
+#else
+# define SWIGEXPORT(a) a
+#endif
+
+#ifdef SWIG_GLOBAL
+#define SWIGRUNTIME(a) SWIGEXPORT(a)
+#else
+#define SWIGRUNTIME(a) static a
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct swig_type_info {
+ char *name;
+ void *(*converter)(void *);
+ char *str;
+ struct swig_type_info *next;
+ struct swig_type_info *prev;
+} swig_type_info;
+
+#ifdef SWIG_NOINCLUDE
+SWIGEXPORT(swig_type_info *) SWIG_TypeRegister(swig_type_info *);
+SWIGEXPORT(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *);
+SWIGEXPORT(void *) SWIG_TypeCast(swig_type_info *, void *);
+#else
+
+static swig_type_info *swig_type_list = 0;
+
+/* Register a type mapping with the type-checking */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeRegister(swig_type_info *ti)
+{
+ swig_type_info *tc, *head, *ret, *next;
+ /* Check to see if this type has already been registered */
+ tc = swig_type_list;
+ while (tc) {
+ if (strcmp(tc->name, ti->name) == 0) {
+ /* Already exists in the table. Just add additional types to the list */
+ head = tc;
+ next = tc->next;
+ goto l1;
+ }
+ tc = tc->prev;
+ }
+ head = ti;
+ next = 0;
+
+ /* Place in list */
+ ti->prev = swig_type_list;
+ swig_type_list = ti;
+
+ /* Build linked lists */
+ l1:
+ ret = head;
+ tc = ti + 1;
+ /* Patch up the rest of the links */
+ while (tc->name) {
+ head->next = tc;
+ tc->prev = head;
+ head = tc;
+ tc++;
+ }
+ head->next = next;
+ return ret;
+}
+
+/* Check the typename */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeCheck(char *c, swig_type_info *ty)
+{
+ swig_type_info *s;
+ if (!ty) return 0; /* Void pointer */
+ s = ty->next; /* First element always just a name */
+ while (s) {
+ if (strcmp(s->name,c) == 0) {
+ if (s == ty->next) return s;
+ /* Move s to the top of the linked list */
+ s->prev->next = s->next;
+ if (s->next) {
+ s->next->prev = s->prev;
+ }
+ /* Insert s as second element in the list */
+ s->next = ty->next;
+ if (ty->next) ty->next->prev = s;
+ ty->next = s;
+ return s;
+ }
+ s = s->next;
+ }
+ return 0;
+}
+
+/* Cast a pointer (needed for C++ inheritance */
+SWIGRUNTIME(void *)
+SWIG_TypeCast(swig_type_info *ty, void *ptr)
+{
+ if ((!ty) || (!ty->converter)) return ptr;
+ return (*ty->converter)(ptr);
+}
+
+/* Search for a swig_type_info structure */
+SWIGRUNTIME(void *)
+SWIG_TypeQuery(const char *name) {
+ swig_type_info *ty = swig_type_list;
+ while (ty) {
+ if (ty->str && (strcmp(name,ty->str) == 0)) return ty;
+ if (ty->name && (strcmp(name,ty->name) == 0)) return ty;
+ ty = ty->prev;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/***********************************************************************
+ * python.swg
+ *
+ * This file contains the runtime support for Python modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ ************************************************************************/
+
+#include <stdlib.h>
+#include "Python.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_PY_INT 1
+#define SWIG_PY_FLOAT 2
+#define SWIG_PY_STRING 3
+#define SWIG_PY_POINTER 4
+
+/* Constant information structure */
+typedef struct swig_const_info {
+ int type;
+ char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_const_info;
+
+#ifdef SWIG_NOINCLUDE
+
+SWIGEXPORT(PyObject *) SWIG_newvarlink();
+SWIGEXPORT(void) SWIG_addvarlink(PyObject *, char *, PyObject *(*)(void), int (*)(PyObject *));
+SWIGEXPORT(int) SWIG_ConvertPtr(PyObject *, void **, swig_type_info *, int);
+SWIGEXPORT(void) SWIG_MakePtr(char *c, void *, swig_type_info *);
+SWIGEXPORT(PyObject *) SWIG_NewPointerObj(void *, swig_type_info *);
+SWIGEXPORT(void) SWIG_InstallConstants(PyObject *d, swig_const_info constants[]);
+
+#else
+
+/* -----------------------------------------------------------------------------
+ * global variable support code.
+ * ----------------------------------------------------------------------------- */
+
+typedef struct swig_globalvar {
+ char *name; /* Name of global variable */
+ PyObject *(*get_attr)(void); /* Return the current value */
+ int (*set_attr)(PyObject *); /* Set the value */
+ struct swig_globalvar *next;
+} swig_globalvar;
+
+typedef struct swig_varlinkobject {
+ PyObject_HEAD
+ swig_globalvar *vars;
+} swig_varlinkobject;
+
+static PyObject *
+swig_varlink_repr(swig_varlinkobject *v) {
+ v = v;
+ return PyString_FromString("<Global variables>");
+}
+
+static int
+swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) {
+ swig_globalvar *var;
+ flags = flags;
+ fprintf(fp,"Global variables { ");
+ for (var = v->vars; var; var=var->next) {
+ fprintf(fp,"%s", var->name);
+ if (var->next) fprintf(fp,", ");
+ }
+ fprintf(fp," }\n");
+ return 0;
+}
+
+static PyObject *
+swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->get_attr)();
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return NULL;
+}
+
+static int
+swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->set_attr)(p);
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return 1;
+}
+
+statichere PyTypeObject varlinktype = {
+ PyObject_HEAD_INIT(0)
+ 0,
+ "swigvarlink", /* Type name */
+ sizeof(swig_varlinkobject), /* Basic size */
+ 0, /* Itemsize */
+ 0, /* Deallocator */
+ (printfunc) swig_varlink_print, /* Print */
+ (getattrfunc) swig_varlink_getattr, /* get attr */
+ (setattrfunc) swig_varlink_setattr, /* Set attr */
+ 0, /* tp_compare */
+ (reprfunc) swig_varlink_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_mapping*/
+ 0, /* tp_hash */
+};
+
+/* Create a variable linking object for use later */
+SWIGRUNTIME(PyObject *)
+SWIG_newvarlink(void) {
+ swig_varlinkobject *result = 0;
+ result = PyMem_NEW(swig_varlinkobject,1);
+ varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */
+ result->ob_type = &varlinktype;
+ result->vars = 0;
+ result->ob_refcnt = 0;
+ Py_XINCREF((PyObject *) result);
+ return ((PyObject*) result);
+}
+
+SWIGRUNTIME(void)
+SWIG_addvarlink(PyObject *p, char *name,
+ PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+ swig_varlinkobject *v;
+ swig_globalvar *gv;
+ v= (swig_varlinkobject *) p;
+ gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+ gv->name = (char *) malloc(strlen(name)+1);
+ strcpy(gv->name,name);
+ gv->get_attr = get_attr;
+ gv->set_attr = set_attr;
+ gv->next = v->vars;
+ v->vars = gv;
+}
+/* Convert a pointer value */
+SWIGRUNTIME(int)
+SWIG_ConvertPtr(PyObject *obj, void **ptr, swig_type_info *ty, int flags) {
+ unsigned long p;
+ register int d;
+ swig_type_info *tc;
+ char *c;
+ static PyObject *SWIG_this = 0;
+ int newref = 0;
+
+ if (!obj || (obj == Py_None)) {
+ *ptr = 0;
+ return 0;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ if (!(PyCObject_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyCObject_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ *ptr = PyCObject_AsVoidPtr(obj);
+ c = (char *) PyCObject_GetDesc(obj);
+ if (newref) Py_DECREF(obj);
+ goto cobject;
+#else
+ if (!(PyString_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyString_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c = PyString_AsString(obj);
+ p = 0;
+ /* Pointer values must start with leading underscore */
+ if (*c != '_') {
+ *ptr = (void *) 0;
+ if (strcmp(c,"NULL") == 0) {
+ if (newref) Py_DECREF(obj);
+ return 0;
+ } else {
+ if (newref) Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c++;
+ /* Extract hex value from pointer */
+ while ((d = *c)) {
+ if ((d >= '0') && (d <= '9'))
+ p = (p << 4) + (d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ p = (p << 4) + (d - ('a'-10));
+ else
+ break;
+ c++;
+ }
+ *ptr = (void *) p;
+ if (newref) Py_DECREF(obj);
+#endif
+
+#ifdef SWIG_COBJECT_TYPES
+cobject:
+#endif
+
+ if (ty) {
+ tc = SWIG_TypeCheck(c,ty);
+ if (!tc) goto type_error;
+ *ptr = SWIG_TypeCast(tc,(void*)p);
+ }
+ return 0;
+
+type_error:
+
+ if (flags) {
+ if (ty) {
+ char *temp = (char *) malloc(64+strlen(ty->name));
+ sprintf(temp,"Type error. Expected %s", ty->name);
+ PyErr_SetString(PyExc_TypeError, temp);
+ free((char *) temp);
+ } else {
+ PyErr_SetString(PyExc_TypeError,"Expected a pointer");
+ }
+ }
+ return -1;
+}
+
+/* Take a pointer and convert it to a string */
+SWIGRUNTIME(void)
+SWIG_MakePtr(char *c, void *ptr, swig_type_info *ty) {
+ static char hex[17] = "0123456789abcdef";
+ unsigned long p, s;
+ char result[32], *r;
+ r = result;
+ p = (unsigned long) ptr;
+ if (p > 0) {
+ while (p > 0) {
+ s = p & 0xf;
+ *(r++) = hex[s];
+ p = p >> 4;
+ }
+ *r = '_';
+ while (r >= result)
+ *(c++) = *(r--);
+ strcpy (c, ty->name);
+ } else {
+ strcpy (c, "NULL");
+ }
+}
+
+/* Create a new pointer object */
+SWIGRUNTIME(PyObject *)
+SWIG_NewPointerObj(void *ptr, swig_type_info *type) {
+ char result[512];
+ PyObject *robj;
+ if (!ptr) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ robj = PyCObject_FromVoidPtrAndDesc((void *) ptr, type->name, NULL);
+#else
+ SWIG_MakePtr(result,ptr,type);
+ robj = PyString_FromString(result);
+#endif
+ return robj;
+}
+
+/* Install Constants */
+SWIGRUNTIME(void)
+SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) {
+ int i;
+ PyObject *obj;
+ for (i = 0; constants[i].type; i++) {
+ switch(constants[i].type) {
+ case SWIG_PY_INT:
+ obj = PyInt_FromLong(constants[i].lvalue);
+ break;
+ case SWIG_PY_FLOAT:
+ obj = PyFloat_FromDouble(constants[i].dvalue);
+ break;
+ case SWIG_PY_STRING:
+ obj = PyString_FromString((char *) constants[i].pvalue);
+ break;
+ case SWIG_PY_POINTER:
+ obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype);
+ break;
+ default:
+ obj = 0;
+ break;
+ }
+ if (obj) {
+ PyDict_SetItemString(d,constants[i].name,obj);
+ Py_DECREF(obj);
+ }
+ }
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_DBFFile swig_types[0]
+static swig_type_info *swig_types[2];
+
+/* -------- TYPES TABLE (END) -------- */
+
+
+/*-----------------------------------------------
+ @(target):= dbflibc.so
+ ------------------------------------------------*/
+#define SWIG_init initdbflibc
+
+#define SWIG_name "dbflibc"
+
+#include "shapefil.h"
+
+
+/* Read one attribute from the dbf handle and return it as a new python object
+ *
+ * If an error occurs, set the appropriate Python exception and return
+ * NULL.
+ *
+ * Assume that the values of the record and field arguments are valid.
+ * The name argument will be passed to DBFGetFieldInfo as is and should
+ * thus be either NULL or a pointer to an array of at least 12 chars
+ */
+static PyObject *
+do_read_attribute(DBFInfo * handle, int record, int field, char * name)
+{
+ int type, width;
+ PyObject *value;
+
+ type = DBFGetFieldInfo(handle, field, name, &width, NULL);
+ /* For strings NULL and the empty string are indistinguishable
+ * in DBF files. We prefer empty strings instead for backwards
+ * compatibility reasons because older wrapper versions returned
+ * emtpy strings as empty strings.
+ */
+ if (type != FTString && DBFIsAttributeNULL(handle, record, field))
+ {
+ value = Py_None;
+ Py_INCREF(value);
+ }
+ else
+ {
+ switch (type)
+ {
+ case FTString:
+ {
+ const char * temp = DBFReadStringAttribute(handle, record, field);
+ if (temp)
+ {
+ value = PyString_FromString(temp);
+ }
+ else
+ {
+ PyErr_Format(PyExc_IOError,
+ "Can't read value for row %d column %d",
+ record, field);
+ value = NULL;
+ }
+ break;
+ }
+ case FTInteger:
+ value = PyInt_FromLong(DBFReadIntegerAttribute(handle, record,
+ field));
+ break;
+ case FTDouble:
+ value = PyFloat_FromDouble(DBFReadDoubleAttribute(handle, record,
+ field));
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError, "Invalid field data type %d",
+ type);
+ value = NULL;
+ }
+ }
+ if (!value)
+ return NULL;
+
+ return value;
+}
+
+/* the read_attribute method. Return the value of the given record and
+ * field as a python object of the appropriate type.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ */
+
+static PyObject *
+DBFInfo_read_attribute(DBFInfo * handle, int record, int field)
+{
+ if (record < 0 || record >= DBFGetRecordCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "record index %d out of bounds (record count: %d)",
+ record, DBFGetRecordCount(handle));
+ return NULL;
+ }
+
+ if (field < 0 || field >= DBFGetFieldCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "field index %d out of bounds (field count: %d)",
+ field, DBFGetFieldCount(handle));
+ return NULL;
+ }
+
+ return do_read_attribute(handle, record, field, NULL);
+}
+
+
+/* the read_record method. Return the record record as a dictionary with
+ * whose keys are the names of the fields, and their values as the
+ * appropriate Python type.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ */
+
+static PyObject *
+DBFInfo_read_record(DBFInfo * handle, int record)
+{
+ int num_fields;
+ int i;
+ int type, width;
+ char name[12];
+ PyObject *dict;
+ PyObject *value;
+
+ if (record < 0 || record >= DBFGetRecordCount(handle))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "record index %d out of bounds (record count: %d)",
+ record, DBFGetRecordCount(handle));
+ return NULL;
+ }
+
+ dict = PyDict_New();
+ if (!dict)
+ return NULL;
+
+ num_fields = DBFGetFieldCount(handle);
+ for (i = 0; i < num_fields; i++)
+ {
+ value = do_read_attribute(handle, record, i, name);
+ if (!value)
+ goto fail;
+
+ PyDict_SetItemString(dict, name, value);
+ Py_DECREF(value);
+ }
+
+ return dict;
+
+ fail:
+ Py_XDECREF(dict);
+ return NULL;
+}
+
+/* the write_record method. Write the record record given wither as a
+ * dictionary or a sequence (i.e. a list or a tuple).
+ *
+ * If it's a dictionary the keys must be the names of the fields and
+ * their value must have a suitable type. Only the fields actually
+ * contained in the dictionary are written. Fields for which there's no
+ * item in the dict are not modified.
+ *
+ * If it's a sequence, all fields must be present in the right order.
+ *
+ * In case of error, set a python exception and return NULL. Since that
+ * value will be returned to the python interpreter as is, the
+ * interpreter should recognize the exception.
+ *
+ * The method is implemented with two c-functions, write_field to write
+ * a single field and DBFInfo_write_record as the front-end.
+ */
+
+
+/* write a single field of a record. */
+static int
+write_field(DBFHandle handle, int record, int field, int type,
+ PyObject * value)
+{
+ char * string_value;
+ int int_value;
+ double double_value;
+
+ if (value == Py_None)
+ {
+ if (!DBFWriteNULLAttribute(handle, record, field))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write NULL field %d of record %d",
+ field, record);
+ return 0;
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case FTString:
+ string_value = PyString_AsString(value);
+ if (!string_value)
+ return 0;
+ if (!DBFWriteStringAttribute(handle, record, field, string_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ case FTInteger:
+ int_value = PyInt_AsLong(value);
+ if (int_value == -1 && PyErr_Occurred())
+ return 0;
+ if (!DBFWriteIntegerAttribute(handle, record, field, int_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ case FTDouble:
+ double_value = PyFloat_AsDouble(value);
+ if (double_value == -1 && PyErr_Occurred())
+ return 0;
+ if (!DBFWriteDoubleAttribute(handle, record, field, double_value))
+ {
+ PyErr_Format(PyExc_IOError,
+ "can't write field %d of record %d",
+ field, record);
+ return 0;
+ }
+ break;
+
+ default:
+ PyErr_Format(PyExc_TypeError, "Invalid field data type %d", type);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static
+PyObject *
+DBFInfo_write_record(DBFHandle handle, int record, PyObject *record_object)
+{
+ int num_fields;
+ int i, length;
+ int type, width;
+ char name[12];
+ PyObject * value = NULL;
+
+ num_fields = DBFGetFieldCount(handle);
+
+ /* We used to use PyMapping_Check to test whether record_object is a
+ * dictionary like object instead of PySequence_Check to test
+ * whether it's a sequence. Unfortunately in Python 2.3
+ * PyMapping_Check returns true for lists and tuples too so the old
+ * approach doesn't work anymore.
+ */
+ if (PySequence_Check(record_object))
+ {
+ /* It's a sequence object. Iterate through all items in the
+ * sequence and write them to the appropriate field.
+ */
+ length = PySequence_Length(record_object);
+ if (length != num_fields)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "record must have one item for each field");
+ goto fail;
+ }
+ for (i = 0; i < length; i++)
+ {
+ type = DBFGetFieldInfo(handle, i, name, &width, NULL);
+ value = PySequence_GetItem(record_object, i);
+ if (value)
+ {
+ if (!write_field(handle, record, i, type, value))
+ goto fail;
+ Py_DECREF(value);
+ }
+ else
+ {
+ goto fail;
+ }
+ }
+ }
+ else
+ {
+ /* It's a dictionary-like object. Iterate over the names of the
+ * known fields and write the corresponding item
+ */
+ for (i = 0; i < num_fields; i++)
+ {
+ type = DBFGetFieldInfo(handle, i, name, &width, NULL);
+
+ /* if the dictionary has the key name write that object to
+ * the appropriate field, other wise just clear the python
+ * exception and do nothing.
+ */
+ value = PyMapping_GetItemString(record_object, name);
+ if (value)
+ {
+ if (!write_field(handle, record, i, type, value))
+ goto fail;
+ Py_DECREF(value);
+ }
+ else
+ {
+ PyErr_Clear();
+ }
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ fail:
+ Py_XDECREF(value);
+ return NULL;
+}
+
+static
+void
+DBFInfo_commit(DBFHandle handle)
+{
+#if HAVE_UPDATE_HEADER
+ DBFUpdateHeader(handle);
+#endif
+}
+
+static PyObject* l_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyList_Check(target)) {
+ o2 = target;
+ target = PyList_New(0);
+ PyList_Append(target, o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(target,o);
+ Py_XDECREF(o);
+ }
+ return target;
+}
+
+static PyObject* t_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ PyObject* o3;
+
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyTuple_Check(target)) {
+ o2 = target;
+ target = PyTuple_New(1);
+ PyTuple_SetItem(target, 0, o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SetItem(o3, 0, o);
+
+ o2 = target;
+ target = PySequence_Concat(o2, o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+ return target;
+}
+
+#define SWIG_MemoryError 1
+#define SWIG_IOError 2
+#define SWIG_RuntimeError 3
+#define SWIG_IndexError 4
+#define SWIG_TypeError 5
+#define SWIG_DivisionByZero 6
+#define SWIG_OverflowError 7
+#define SWIG_SyntaxError 8
+#define SWIG_ValueError 9
+#define SWIG_SystemError 10
+#define SWIG_UnknownError 99
+
+static void _SWIG_exception(int code, char *msg) {
+ switch(code) {
+ case SWIG_MemoryError:
+ PyErr_SetString(PyExc_MemoryError,msg);
+ break;
+ case SWIG_IOError:
+ PyErr_SetString(PyExc_IOError,msg);
+ break;
+ case SWIG_RuntimeError:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ case SWIG_IndexError:
+ PyErr_SetString(PyExc_IndexError,msg);
+ break;
+ case SWIG_TypeError:
+ PyErr_SetString(PyExc_TypeError,msg);
+ break;
+ case SWIG_DivisionByZero:
+ PyErr_SetString(PyExc_ZeroDivisionError,msg);
+ break;
+ case SWIG_OverflowError:
+ PyErr_SetString(PyExc_OverflowError,msg);
+ break;
+ case SWIG_SyntaxError:
+ PyErr_SetString(PyExc_SyntaxError,msg);
+ break;
+ case SWIG_ValueError:
+ PyErr_SetString(PyExc_ValueError,msg);
+ break;
+ case SWIG_SystemError:
+ PyErr_SetString(PyExc_SystemError,msg);
+ break;
+ default:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ }
+}
+
+#define SWIG_exception(a,b) { _SWIG_exception(a,b); return NULL; }
+
+ typedef struct {
+ DBFHandle handle;
+ } DBFFile;
+
+#define NOCHECK_delete_DBFFile
+#define NOCHECK_DBFFile_close
+
+ DBFFile * open_DBFFile(const char * file, const char * mode)
+ {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFOpen(file, mode);
+ return self;
+ }
+
+ DBFFile * create_DBFFile(const char * file)
+ {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFCreate(file);
+ return self;
+ }
+#ifdef __cplusplus
+extern "C" {
+#endif
+static PyObject *_wrap_open(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ char *arg1 = "rb" ;
+ DBFFile *result ;
+
+ if(!PyArg_ParseTuple(args,"s|s:open",&arg0,&arg1)) return NULL;
+ {
+ result = (DBFFile *)open_DBFFile((char const *)arg0,(char const *)arg1);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "open_DBFFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_DBFFile);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_create(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ DBFFile *result ;
+
+ if(!PyArg_ParseTuple(args,"s:create",&arg0)) return NULL;
+ {
+ result = (DBFFile *)create_DBFFile((char const *)arg0);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "create_DBFFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_DBFFile);
+ return resultobj;
+}
+
+
+DBFFile * new_DBFFile(char const *file,char const *mode) {
+ {
+ DBFFile * self = malloc(sizeof(DBFFile));
+ if (self)
+ self->handle = DBFOpen(file, mode);
+ return self;
+ }
+}
+
+
+static PyObject *_wrap_new_DBFFile(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ char *arg1 = "rb" ;
+ DBFFile *result ;
+
+ if(!PyArg_ParseTuple(args,"s|s:new_DBFFile",&arg0,&arg1)) return NULL;
+ {
+ result = (DBFFile *)new_DBFFile((char const *)arg0,(char const *)arg1);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "new_DBFFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_DBFFile);
+ return resultobj;
+}
+
+
+void delete_DBFFile(DBFFile *self) {
+ {
+ if (self->handle)
+ DBFClose(self->handle);
+ free(self);
+ }
+}
+
+
+static PyObject *_wrap_delete_DBFFile(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:delete_DBFFile",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_delete_DBFFile
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ delete_DBFFile(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+void DBFFile_close(DBFFile *self) {
+ {
+ if (self->handle)
+ DBFClose(self->handle);
+ self->handle = NULL;
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_close(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:DBFFile_close",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_close
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ DBFFile_close(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+int DBFFile_field_count(DBFFile *self) {
+ {
+ return DBFGetFieldCount(self->handle);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_field_count(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"O:DBFFile_field_count",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_field_count
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (int )DBFFile_field_count(arg0);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+int DBFFile_record_count(DBFFile *self) {
+ {
+ return DBFGetRecordCount(self->handle);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_record_count(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"O:DBFFile_record_count",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_record_count
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (int )DBFFile_record_count(arg0);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+int DBFFile_field_info(DBFFile *self,int iField,char *fieldname_out,int *output_width,int *output_decimals) {
+ {
+ return DBFGetFieldInfo(self->handle, iField, fieldname_out,
+ output_width, output_decimals);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_field_info(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ int arg1 ;
+ char *arg2 ;
+ int *arg3 ;
+ int *arg4 ;
+ char temp[12] ;
+ int temp0 ;
+ int temp1 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ {
+ arg2 = temp;
+ }
+ {
+ arg3 = &temp0;
+ }
+ {
+ arg4 = &temp1;
+ }
+ if(!PyArg_ParseTuple(args,"Oi:DBFFile_field_info",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_field_info
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (int )DBFFile_field_info(arg0,arg1,arg2,arg3,arg4);
+ resultobj = PyInt_FromLong((long)result);
+ {
+ PyObject * string = PyString_FromString(arg2);
+ resultobj = t_output_helper(resultobj,string);
+ }
+ {
+ PyObject *o;
+ o = PyInt_FromLong((long) (*arg3));
+ resultobj = t_output_helper(resultobj, o);
+ }
+ {
+ PyObject *o;
+ o = PyInt_FromLong((long) (*arg4));
+ resultobj = t_output_helper(resultobj, o);
+ }
+ return resultobj;
+}
+
+
+PyObject * DBFFile_read_record(DBFFile *self,int record) {
+ {
+ return DBFInfo_read_record(self->handle, record);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_read_record(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:DBFFile_read_record",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_read_record
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (PyObject *)DBFFile_read_record(arg0,arg1);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+PyObject * DBFFile_read_attribute(DBFFile *self,int record,int field) {
+ {
+ return DBFInfo_read_attribute(self->handle, record, field);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_read_attribute(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ int arg1 ;
+ int arg2 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"Oii:DBFFile_read_attribute",&argo0,&arg1,&arg2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_read_attribute
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (PyObject *)DBFFile_read_attribute(arg0,arg1,arg2);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+int DBFFile_add_field(DBFFile *self,char const *pszFieldName,DBFFieldType eType,int nWidth,int nDecimals) {
+ {
+ return DBFAddField(self->handle, pszFieldName, eType, nWidth,
+ nDecimals);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_add_field(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ char *arg1 ;
+ int arg2 ;
+ int arg3 ;
+ int arg4 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"Osiii:DBFFile_add_field",&argo0,&arg1,&arg2,&arg3,&arg4)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_add_field
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ {
+ result = (int )DBFFile_add_field(arg0,(char const *)arg1,(DBFFieldType )arg2,arg3,arg4);
+ ;
+ if (result < 0)
+ {
+ SWIG_exception(SWIG_RuntimeError, "add_field failed");
+ }
+ }resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+PyObject * DBFFile_write_record(DBFFile *self,int record,PyObject *dict_or_sequence) {
+ {
+ return DBFInfo_write_record(self->handle, record,
+ dict_or_sequence);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_write_record(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ int arg1 ;
+ PyObject *arg2 ;
+ PyObject * argo0 =0 ;
+ PyObject * obj2 = 0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"OiO:DBFFile_write_record",&argo0,&arg1,&obj2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ arg2 = obj2;
+ }
+ {
+ #ifndef NOCHECK_DBFFile_write_record
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ result = (PyObject *)DBFFile_write_record(arg0,arg1,arg2);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+void DBFFile_commit(DBFFile *self) {
+ {
+ DBFInfo_commit(self->handle);
+ }
+}
+
+
+static PyObject *_wrap_DBFFile_commit(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ DBFFile *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:DBFFile_commit",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_DBFFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_DBFFile_commit
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "dbffile already closed");
+ #endif
+ }
+ DBFFile_commit(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyMethodDef dbflibcMethods[] = {
+ { "open", _wrap_open, METH_VARARGS },
+ { "create", _wrap_create, METH_VARARGS },
+ { "new_DBFFile", _wrap_new_DBFFile, METH_VARARGS },
+ { "delete_DBFFile", _wrap_delete_DBFFile, METH_VARARGS },
+ { "DBFFile_close", _wrap_DBFFile_close, METH_VARARGS },
+ { "DBFFile_field_count", _wrap_DBFFile_field_count, METH_VARARGS },
+ { "DBFFile_record_count", _wrap_DBFFile_record_count, METH_VARARGS },
+ { "DBFFile_field_info", _wrap_DBFFile_field_info, METH_VARARGS },
+ { "DBFFile_read_record", _wrap_DBFFile_read_record, METH_VARARGS },
+ { "DBFFile_read_attribute", _wrap_DBFFile_read_attribute, METH_VARARGS },
+ { "DBFFile_add_field", _wrap_DBFFile_add_field, METH_VARARGS },
+ { "DBFFile_write_record", _wrap_DBFFile_write_record, METH_VARARGS },
+ { "DBFFile_commit", _wrap_DBFFile_commit, METH_VARARGS },
+ { NULL, NULL }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_DBFFile[] = {{"_p_DBFFile", 0, "DBFFile *"},{"_p_DBFFile"},{0}};
+
+static swig_type_info *swig_types_initial[] = {
+_swigt__p_DBFFile,
+0
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+ { SWIG_PY_INT, "FTString", (long) FTString, 0, 0, 0},
+ { SWIG_PY_INT, "FTInteger", (long) FTInteger, 0, 0, 0},
+ { SWIG_PY_INT, "FTDouble", (long) FTDouble, 0, 0, 0},
+ { SWIG_PY_INT, "FTInvalid", (long) FTInvalid, 0, 0, 0},
+ { SWIG_PY_INT, "_have_commit", (long) HAVE_UPDATE_HEADER, 0, 0, 0},
+{0}};
+
+static PyObject *SWIG_globals;
+#ifdef __cplusplus
+extern "C"
+#endif
+SWIGEXPORT(void) initdbflibc(void) {
+ PyObject *m, *d;
+ int i;
+ SWIG_globals = SWIG_newvarlink();
+ m = Py_InitModule("dbflibc", dbflibcMethods);
+ d = PyModule_GetDict(m);
+ for (i = 0; swig_types_initial[i]; i++) {
+ swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);
+ }
+ SWIG_InstallConstants(d,swig_const_table);
+
+# if PY_VERSION_HEX >=0x02040000
+ /* because we are in a python module now, we can give out
+ * pointers to python's locale agonistic function
+ * XXX this clearly is a hack
+ */
+ DBFSetatof_function(&PyOS_ascii_atof);
+# endif
+
+}
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/pyshapelib_api.h
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/pyshapelib_api.h 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/pyshapelib_api.h 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,41 @@
+/* Header file for the PyShapelib API for other Python modules */
+/* $Revision: 1611 $ */
+
+#ifndef PYSHAPELIB_API_H
+#define PYSHAPELIB_API_H
+
+typedef struct {
+ /* Shapefile functions */
+ SHPObject * (*SHPReadObject)(SHPHandle hSHP, int iShape);
+ void (*SHPDestroyObject)(SHPObject * psObject);
+
+ /* SHPTree functions */
+ SHPTree * (*SHPCreateTree)(SHPHandle hSHP, int nDimension, int nMaxDepth,
+ double *padfBoundsMin, double *padfBoundsMax);
+ void (*SHPDestroyTree)(SHPTree * hTree);
+ int * (*SHPTreeFindLikelyShapes)(SHPTree * hTree, double * padfBoundsMin,
+ double * padfBoundsMax, int *);
+} PyShapeLibAPI;
+
+
+/* Macro to import the shapelib module, extract the API pointer and
+ * assign it to the variable given as argument */
+#define PYSHAPELIB_IMPORT_API(apivariable) \
+{ \
+ PyObject * shapelib = PyImport_ImportModule("shapelibc"); \
+ if (shapelib) \
+ { \
+ PyObject * c_api_func = PyObject_GetAttrString(shapelib, "c_api"); \
+ if (c_api_func) \
+ { \
+ PyObject * cobj = PyObject_CallObject(c_api_func, NULL); \
+ if (cobj) \
+ { \
+ (apivariable) = (PyShapeLibAPI*)PyCObject_AsVoidPtr(cobj); \
+ } \
+ } \
+ } \
+}
+
+
+#endif /* PYSHAPELIB_API_H */
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/pytest.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/pytest.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/pytest.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,128 @@
+import shapelib, dbflib, shptree
+
+#
+# The the shapefile module
+#
+
+def make_shapefile(filename):
+ # Create a shapefile with polygons
+ outfile = shapelib.create(filename, shapelib.SHPT_POLYGON)
+
+ # Create one very simple polygon and write it to the shapefile. The
+ # vertices should be given in clockwise order to comply with the
+ # shapefile specification.
+ obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
+ [[(10, 10), (10, 20), (20, 20), (10, 10)]])
+ print obj.extents()
+ print obj.vertices()
+ outfile.write_object(-1, obj)
+
+ # Create a polygon with a hole. Note that according to the
+ # shapefile specification, the vertices of the outer ring have to be
+ # in clockwise order and the inner rings have to be in counter
+ # clockwise order.
+ #
+ # There's an optional fourth parameter which when given must be a
+ # list of part types, one for each part of the shape. For polygons,
+ # the part type is always shapelib.SHPP_RING, though. The part
+ # types are only relevant for SHPT_MULTIPATCH shapefiles.
+ obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
+ [[(0, 0), (0, 40), (40, 40), (40, 0), (0, 0)],
+ [(10, 10), (20, 10), (20, 20), (10, 20),(10, 10)],
+ ])
+ print obj.extents()
+ print obj.vertices()
+ outfile.write_object(-1, obj)
+
+ # close the file.
+ outfile.close()
+
+def read_shapefile(filename):
+ # open the shapefile
+ shp = shapelib.ShapeFile(filename)
+
+ # the info method returns a tuple (num_shapes, type, min, max) where
+ # num_shapes is the number of shapes, type is the type code (one of
+ # the SHPT* constants defined in the shapelib module) and min and
+ # max are 4-element lists with the min. and max. values of the
+ # vertices.
+ print shp.info()
+
+ # read_object reads a shape
+ obj = shp.read_object(0)
+
+ # The vertices method returns the shape as a list of lists of tuples.
+ print obj.vertices()[0][:10]
+
+ # The extents returns a tuple with two 4-element lists with the min.
+ # and max. values of the vertices.
+ print obj.extents()
+
+ # The type attribute is the type code (one of the SHPT* constants
+ # defined in the shapelib module)
+ print obj.type
+
+ # The id attribute is the shape id
+ print obj.id
+
+ # the cobject method returns a PyCObject containing the shapelib
+ # SHPHandle. This is useful for passing shapefile objects to
+ # C-Python extensions.
+ print shp.cobject()
+
+ # build a quad tree from the shapefile. The first argument must be
+ # the return value of the shape file object's cobject method (this
+ # is currently needed to access the shape file at the C-level). The
+ # second argument is the dimension and the third the maximum depth.
+ # 0 means to guess an appropriate depth
+ tree = shptree.SHPTree(shp.cobject(), 2, 0)
+
+ # Retrieve the ids for a region. Here we just use the extents of the
+ # object previously read from the shapefile
+ minima, maxima = obj.extents()
+ print tree.find_shapes(minima[:2], maxima[:2])
+
+
+make_shapefile("testfile")
+read_shapefile("testfile")
+
+#
+# Test the DBF file module.
+#
+
+def make_dbf(file):
+ # create a new dbf file and add three fields.
+ dbf = dbflib.create(file)
+ dbf.add_field("NAME", dbflib.FTString, 20, 0)
+ dbf.add_field("INT", dbflib.FTInteger, 10, 0)
+ dbf.add_field("FLOAT", dbflib.FTDouble, 10, 4)
+
+def add_dbf_records(file):
+ # add some records to file
+ dbf = dbflib.open(file, "r+b")
+ # Records can be added as a dictionary...
+ dbf.write_record(0, {'NAME': "Weatherwax", "INT":1, "FLOAT":3.1415926535})
+ # ... or as a sequence
+ dbf.write_record(1, ("Ogg", 2, -1000.1234))
+
+def list_dbf(file):
+ # print the contents of a dbf file to stdout
+ dbf = dbflib.DBFFile(file)
+ print "%d records, %d fields" % (dbf.record_count(), dbf.field_count())
+ format = ""
+ for i in range(dbf.field_count()):
+ type, name, len, decc = dbf.field_info(i)
+ if type == 0:
+ format = format + " %%(%s)%ds" % (name, len)
+ elif type == 1:
+ format = format + " %%(%s)%dd" % (name, len)
+ elif type == 2:
+ format = format + " %%(%s)%dg" % (name, len)
+ print format
+ for i in range(dbf.record_count()):
+ print format % dbf.read_record(i)
+
+
+make_dbf("testfile")
+add_dbf_records("testfile")
+list_dbf("testfile")
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/setup.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/setup.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/setup.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,72 @@
+
+import os
+import sys
+from distutils.core import setup, Extension
+from distutils.util import convert_path
+
+# try to determine the directory where the shapelib source files are.
+# There are currently two supported situations.
+#
+# 1. "Standalone" build: the parent directory is the shapelib source
+# directory
+# 2. Built in the Thuban source tree where ../shapelib/ relative to the
+# directory containing this setup.py contains (the relevant parts of)
+# shapelib
+#
+# 3. Binary build with e.g. bdist_rpm. This takes place deep in the
+# build directory.
+
+# os.path expects filenames in OS-specific form so we have to construct
+# the files with os.path functions. distutils, OTOH, uses posix-style
+# filenames exclusively, so we use posix conventions when making
+# filenames for distutils.
+for shp_dir in ["..", "../shapelib", "../../../../../../shapelib"]:
+ if (os.path.isdir(convert_path(shp_dir))
+ and os.path.exists(os.path.join(convert_path(shp_dir), "shpopen.c"))):
+ # shp_dir contains shpopen.c, so assume it's the directory with
+ # the shapefile library to use
+ break
+else:
+ print >>sys.stderr, "no shapelib directory found"
+ sys.exit(1)
+
+def dbf_macros():
+ """Return the macros to define when compiling the dbflib wrapper.
+
+ The returned list specifies one macro, HAVE_UPDATE_HEADER, which is
+ '1' if the dbflib version we will be compiling with has the
+ DBFUpdateHeader function and '0' otherwise. To check whether
+ DBFUpdateHeader is available, we scan shapefil.h for the string
+ 'DBFUpdateHeader'.
+ """
+ f = open(convert_path(shp_dir + "/shapefil.h"))
+ contents = f.read()
+ f.close()
+ if contents.find("DBFUpdateHeader") >= 0:
+ return [("HAVE_UPDATE_HEADER", "1")]
+ else:
+ return [("HAVE_UPDATE_HEADER", "0")]
+
+extensions = [Extension("shapelibc",
+ ["shapelib_wrap.c",
+ shp_dir + "/shpopen.c",
+ shp_dir + "/shptree.c"],
+ include_dirs = [shp_dir]),
+ Extension("shptree",
+ ["shptreemodule.c"],
+ include_dirs = [shp_dir]),
+ Extension("dbflibc",
+ ["dbflib_wrap.c",
+ shp_dir + "/dbfopen.c"],
+ include_dirs = [shp_dir],
+ define_macros = dbf_macros())]
+
+setup(name = "pyshapelib",
+ version = "0.3",
+ description = "Python bindings for shapelib",
+ author = "Bernhard Herzog",
+ author_email = "bh at intevation.de",
+ url = "ftp:intevation.de/users/bh",
+ py_modules = ["shapelib", "dbflib"],
+ ext_modules = extensions)
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.i
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.i 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.i 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,612 @@
+/* SWIG (www.swig.org) interface file for shapelib
+ *
+ * At the moment (Dec 2000) this file is only useful to generate Python
+ * bindings. Invoke swig as follows:
+ *
+ * swig -python -shadow shapelib.i
+ *
+ * to generate shapelib_wrap.c and shapelib.py. shapelib_wrap.c
+ * defines a bunch of Python-functions that wrap the appripriate
+ * shapelib functions and shapelib.py contains an object oriented
+ * wrapper around shapelib_wrap.c.
+ *
+ * Shapelib, and hence this module too, defines two types of objects,
+ * shapes and shapefiles.
+ */
+
+%module shapelib
+
+/*
+ * First, a %{,%}-Block. These blocks are copied verbatim to the
+ * shapelib_wrap.c file and are not parsed by SWIG. This is the place to
+ * import headerfiles and define helper-functions that are needed by the
+ * automatically generated wrappers.
+ */
+
+%{
+
+/* import the shapelib headefile. */
+#include "shapefil.h"
+#include "pyshapelib_api.h"
+
+/*
+ * Rename a few shapelib functions that are effectively methods with
+ * preprocessor macros so that they have the names that swig expects
+ * (e.g. the destructor of SHPObject has to be called delete_SHPObject)
+ */
+
+#define delete_SHPObject SHPDestroyObject
+
+/*
+ * The extents() method of SHPObject.
+ *
+ * Return the extents as a tuple of two 4-element lists with the min.
+ * and max. values of x, y, z, m.
+ */
+static PyObject *
+SHPObject_extents(SHPObject *object)
+{
+ return Py_BuildValue("[dddd][dddd]",
+ object->dfXMin, object->dfYMin, object->dfZMin,
+ object->dfMMin,
+ object->dfXMax, object->dfYMax, object->dfZMax,
+ object->dfMMax);
+}
+
+
+/*
+ * The vertices() method of SHPObject.
+ *
+ * Return the x and y coords of the vertices as a list of lists of
+ * tuples.
+ */
+
+static PyObject* build_vertex_list(SHPObject *object, int index, int length);
+
+static PyObject*
+SHPObject_vertices(SHPObject *object)
+{
+ PyObject *result = NULL;
+ PyObject *part = NULL;
+ int part_idx, vertex_idx;
+ int length = 0;
+
+
+ if (object->nParts > 0)
+ {
+ /* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
+
+ result = PyList_New(object->nParts);
+ if (!result)
+ return NULL;
+
+ for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
+ part_idx++)
+ {
+ if (part_idx < object->nParts - 1)
+ length = (object->panPartStart[part_idx + 1]
+ - object->panPartStart[part_idx]);
+ else
+ length = object->nVertices - object->panPartStart[part_idx];
+
+ part = build_vertex_list(object, vertex_idx, length);
+ if (!part)
+ goto fail;
+
+ if (PyList_SetItem(result, part_idx, part) < 0)
+ goto fail;
+
+ vertex_idx += length;
+ }
+ }
+ else
+ {
+ /* only one part. usual for SHPT_POINT */
+ result = build_vertex_list(object, 0, object->nVertices);
+ }
+
+ return result;
+
+ fail:
+ Py_XDECREF(part);
+ Py_DECREF(result);
+ return NULL;
+}
+
+
+/* Return the length coordinates of the shape object starting at vertex
+ * index as a Python-list of tuples. Helper function for
+ * SHPObject_vertices.
+ */
+static PyObject*
+build_vertex_list(SHPObject *object, int index, int length)
+{
+ int i;
+ PyObject * list;
+ PyObject * vertex = NULL;
+
+ list = PyList_New(length);
+ if (!list)
+ return NULL;
+
+ for (i = 0; i < length; i++, index++)
+ {
+ vertex = Py_BuildValue("dd", object->padfX[index],
+ object->padfY[index]);
+ if (!vertex)
+ goto fail;
+ if (PyList_SetItem(list, i, vertex) < 0)
+ goto fail;
+ }
+
+ return list;
+
+ fail:
+ Py_XDECREF(vertex);
+ Py_DECREF(list);
+ return NULL;
+}
+
+
+
+
+
+/* The constructor of SHPObject. parts is a list of lists of tuples
+ * describing the parts and their vertices just likethe output of the
+ * vertices() method. part_type_list is the list of part-types and may
+ * be NULL. For the meaning of the part-types and their default value
+ * see the Shaplib documentation.
+ */
+SHPObject * new_SHPObject(int type, int id, PyObject * parts,
+ PyObject * part_type_list)
+{
+ /* arrays to hold thex and y coordinates of the vertices */
+ double *xs = NULL, *ys = NULL;
+ /* number of all vertices of all parts */
+ int num_vertices;
+ /* number of parts in the list parts */
+ int num_parts;
+ /* start index of in xs and ys of the part currently worked on */
+ int part_start;
+ /* array of start indices in xs and ys as expected by shapelib */
+ int *part_starts = NULL;
+
+ /* generic counter */
+ int i;
+
+ /* array of part types. holds the converted content of
+ * part_type_list. Stays NULL of part_type_list is NULL
+ */
+ int *part_types = NULL;
+
+ /* temporary python objects referring to the the list items being
+ * worked on.
+ */
+ PyObject * part = NULL, *tuple = NULL;
+
+ /* The result object */
+ SHPObject *result;
+
+ num_parts = PySequence_Length(parts);
+ num_vertices = 0;
+
+ /* parts and part_types have to have the same lengths */
+ if (part_type_list
+ && PySequence_Length(parts) != PySequence_Length(part_type_list))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "parts and part_types have to have the same lengths");
+ return NULL;
+ }
+
+ /* determine how many vertices there are altogether */
+ for (i = 0; i < num_parts; i++)
+ {
+ PyObject * part = PySequence_GetItem(parts, i);
+ if (!part)
+ return NULL;
+ num_vertices += PySequence_Length(part);
+ Py_DECREF(part);
+ }
+
+ /* allocate the memory for the various arrays and check for memory
+ errors */
+ xs = malloc(num_vertices * sizeof(double));
+ ys = malloc(num_vertices * sizeof(double));
+ part_starts = malloc(num_parts * sizeof(int));
+ if (part_type_list)
+ part_types = malloc(num_parts * sizeof(int));
+
+ if (!xs || !ys || !part_starts || (part_type_list && !part_types))
+ {
+ PyErr_NoMemory();
+ goto fail;
+ }
+
+ /* convert the part types */
+ if (part_type_list)
+ {
+ for (i = 0; i < num_parts; i++)
+ {
+ PyObject * otype = PySequence_GetItem(part_type_list, i);
+ if (!otype)
+ return NULL;
+ part_types[i] = PyInt_AsLong(otype);
+ Py_DECREF(otype);
+ }
+ }
+
+ /* convert the list of parts */
+ part_start = 0;
+ for (i = 0; i < num_parts; i++)
+ {
+ int j, length;
+
+ part = PySequence_GetItem(parts, i);
+ length = PySequence_Length(part);
+ part_starts[i] = part_start;
+
+ for (j = 0; j < length; j++)
+ {
+ tuple = PySequence_GetItem(part, j);
+ if (!tuple)
+ goto fail;
+
+ if (!PyArg_ParseTuple(tuple, "dd", xs + part_start + j,
+ ys + part_start + j))
+ {
+ goto fail;
+ }
+ Py_DECREF(tuple);
+ tuple = NULL;
+ }
+ Py_DECREF(part);
+ part = NULL;
+ part_start += length;
+ }
+
+ result = SHPCreateObject(type, id, num_parts, part_starts, part_types,
+ num_vertices, xs, ys, NULL, NULL);
+ free(xs);
+ free(ys);
+ free(part_starts);
+ free(part_types);
+ return result;
+
+ fail:
+ free(xs);
+ free(ys);
+ free(part_starts);
+ free(part_types);
+ Py_XDECREF(part);
+ Py_XDECREF(tuple);
+ return NULL;
+}
+
+%}
+
+
+
+/*
+ * The SWIG Interface definition.
+ */
+
+/* include some common SWIG type definitions and standard exception
+ handling code */
+%include typemaps.i
+%include exception.i
+
+
+/*
+ * SHPObject -- Represents one shape
+ */
+
+/* Exception typemap for the SHPObject constructor. The constructor the
+ the wrapper function defined above which returns NULL in case of
+ error. */
+
+%typemap(python,except) SHPObject*new_SHPObject {
+ $function;
+ if (PyErr_Occurred())
+ return NULL;
+}
+
+/* Define the SHPObject struct for SWIG. This has to have the same name
+ * as the underlying C-struct in shapfil.h, but we don't have to repeat
+ * all the fields here, only those we want to access directly, and we
+ * can define methods for the object oriented interface.
+ */
+
+typedef struct {
+
+ /* The shape object has two read-only attributes: */
+
+ /* The type of the shape. In the c-struct defined the field is
+ * called 'nSHPType' but for the python bindings 'type' is more
+ * appropriate.
+ */
+ %readonly %name(type) int nSHPType;
+
+ /* The id of the shape. Here 'id' is a better name than 'nShapeId'. */
+ %readonly %name(id) int nShapeId;
+
+ /* The methods */
+ %addmethods {
+
+ /* the constructor */
+ SHPObject(int type, int id, PyObject * parts,
+ PyObject * part_types = NULL);
+
+ /* The destructor */
+ ~SHPObject();
+
+ /* extents and vertices correspond to the SHPObject_extents and
+ * SHPObject_vertices defined above
+ */
+ PyObject *extents();
+ PyObject *vertices();
+ }
+} SHPObject;
+
+
+/*
+ * ShapeFile -- Represents the shape file
+ */
+
+/* Here we do things a little different. We define a new C-struct that
+ * holds the SHPHandle. This is mainly done so we can separate the
+ * close() method from the destructor but it also helps with exception
+ * handling.
+ *
+ * After the ShapeFile has been opened or created the handle is not
+ * NULL. The close() method closes the file and sets handle to NULL as
+ * an indicator that the file has been closed.
+ */
+
+/* First, define the C-struct */
+%{
+ typedef struct {
+ SHPHandle handle;
+ } ShapeFile;
+%}
+
+/* define and use some typemaps for the info() method whose
+ * C-implementation has four output parameters that are returned through
+ * pointers passed into the function. SWIG already has definitions for
+ * common types such as int* and we can use those for the first two
+ * parameters:
+ */
+
+%apply int * OUTPUT { int * output_entities }
+%apply int * OUTPUT { int * output_type }
+
+/* for the last two, the 4-element arrays of min- and max-values, we
+ * have to define our own typemaps:
+ */
+%typemap (python,ignore) double * extents(double temp[4]) {
+ $target = temp;
+}
+
+%typemap (python,argout) double * extents {
+ PyObject * list = Py_BuildValue("[dddd]",
+ $source[0], $source[1],
+ $source[2], $source[3]);
+ $target = t_output_helper($target,list);
+}
+
+%apply double * extents { double * output_min_bounds }
+%apply double * extents { double * output_max_bounds }
+
+/* The first argument to the ShapeFile methods is a ShapeFile pointer.
+ * We have to check whether handle is not NULL in most methods but not
+ * all. In the destructor and the close method, it's OK for handle to be
+ * NULL. We achieve this by checking whether the preprocessor macro
+ * NOCHECK_$name is defined. SWIG replaces $name with the name of the
+ * function for which the code is inserted. In the %{,%}-block below we
+ * define the macros for the destructor and the close() method.
+ */
+
+
+%typemap(python,check) ShapeFile *{
+ %#ifndef NOCHECK_$name
+ if (!$target || !$target->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ %#endif
+}
+
+%{
+#define NOCHECK_delete_ShapeFile
+#define NOCHECK_ShapeFile_close
+%}
+
+/* An exception handle for the constructor and the module level open()
+ * and create() functions.
+ *
+ * Annoyingly, we *have* to put braces around the SWIG_exception()
+ * calls, at least in the python case, because of the way the macro is
+ * written. Of course, always putting braces around the branches of an
+ * if-statement is often considered good practice.
+ */
+%typemap(python,except) ShapeFile * {
+ $function;
+ if (!$source)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!$source->handle)
+ {
+ SWIG_exception(SWIG_IOError, "$name failed");
+ }
+}
+
+
+/*
+ * The SWIG-version of the ShapeFile struct.
+ */
+
+typedef struct
+{
+ /* Only methods and no attributes here: */
+ %addmethods {
+
+ /* The constructor. Takes two arguments, the filename and the
+ * optinal mode which are passed through to SHPOpen (due to the
+ * renaming trick)
+ */
+ ShapeFile(char *file, char * mode = "rb") {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPOpen(file, mode);
+ return self;
+ }
+
+ /* The destructor. Equivalent to SHPClose */
+ ~ShapeFile() {
+ if (self->handle)
+ SHPClose(self->handle);
+ free(self);
+ }
+
+ /* close the shape file and set handle to NULL */
+ void close() {
+ if (self->handle)
+ {
+ SHPClose(self->handle);
+ self->handle = NULL;
+ }
+ }
+
+ /* info() -- Return a tuple (NUM_SHAPES, TYPE, MIN, MAX) where
+ * NUM_SHAPES is the number of shapes in the file, TYPE is the
+ * shape type and MIN and MAX are 4-element lists with the min.
+ * and max. values of the data.
+ *
+ * The arguments of the underlying shapelib function SHPGetInfo
+ * are all output parameters. To tell SWIG this, we have defined
+ * some typemaps above
+ */
+ void info(int * output_entities, int * output_type,
+ double * output_min_bounds, double *output_max_bounds) {
+ SHPGetInfo(self->handle, output_entities, output_type,
+ output_min_bounds, output_max_bounds);
+ }
+
+ /* Return object number i */
+ %new SHPObject * read_object(int i) {
+ return SHPReadObject(self->handle, i);
+ }
+
+ /* Write an object */
+ int write_object(int iShape, SHPObject * psObject) {
+ return SHPWriteObject(self->handle, iShape, psObject);
+ }
+
+ /* Return the shapelib SHPHandle as a Python CObject */
+ PyObject * cobject() {
+ return PyCObject_FromVoidPtr(self->handle, NULL);
+ }
+ }
+
+} ShapeFile;
+
+
+/*
+ * Two module level functions, open() and create() that correspond to
+ * SHPOpen and SHPCreate respectively. open() is equivalent to the
+ * ShapeFile constructor.
+ */
+
+%{
+ ShapeFile * open_ShapeFile(const char *filename, const char * mode) {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPOpen(filename, mode);
+ return self;
+ }
+%}
+
+%name(open) %new ShapeFile *open_ShapeFile(const char *filename,
+ const char * mode = "rb");
+
+
+%{
+ ShapeFile * create_ShapeFile(const char *filename, int type) {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPCreate(filename, type);
+ return self;
+ }
+%}
+
+%name(create) %new ShapeFile * create_ShapeFile(const char *filename,
+ int type);
+
+
+/* Module level function to expose some of the shapelib functions linked
+ * with the shapefile C-module to other Python extension modules. This
+ * is a kludge to make a Thuban extension work that reads shapes from
+ * shapefiles opened by the shapefile module.
+ */
+
+%{
+ static PyShapeLibAPI the_api = {
+ SHPReadObject,
+ SHPDestroyObject,
+ SHPCreateTree,
+ SHPDestroyTree,
+ SHPTreeFindLikelyShapes
+ };
+
+ PyObject * c_api() {
+ return PyCObject_FromVoidPtr(&the_api, NULL);
+ }
+%}
+
+PyObject * c_api();
+
+
+/*
+ * Module Level functions
+ */
+
+/* convert shapefile types to names */
+%name(type_name) const char *SHPTypeName(int nSHPType);
+%name(part_type_name) const char *SHPPartTypeName(int nPartType);
+
+
+/*
+ * Finally, constants copied from shapefil.h
+ */
+
+/* -------------------------------------------------------------------- */
+/* Shape types (nSHPType) */
+/* -------------------------------------------------------------------- */
+#define SHPT_NULL 0
+#define SHPT_POINT 1
+#define SHPT_ARC 3
+#define SHPT_POLYGON 5
+#define SHPT_MULTIPOINT 8
+#define SHPT_POINTZ 11
+#define SHPT_ARCZ 13
+#define SHPT_POLYGONZ 15
+#define SHPT_MULTIPOINTZ 18
+#define SHPT_POINTM 21
+#define SHPT_ARCM 23
+#define SHPT_POLYGONM 25
+#define SHPT_MULTIPOINTM 28
+#define SHPT_MULTIPATCH 31
+
+
+/* -------------------------------------------------------------------- */
+/* Part types - everything but SHPT_MULTIPATCH just uses */
+/* SHPP_RING. */
+/* -------------------------------------------------------------------- */
+
+#define SHPP_TRISTRIP 0
+#define SHPP_TRIFAN 1
+#define SHPP_OUTERRING 2
+#define SHPP_INNERRING 3
+#define SHPP_FIRSTRING 4
+#define SHPP_RING 5
+
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,119 @@
+# This file was created automatically by SWIG.
+import shapelibc
+class SHPObject:
+ def __init__(self,*args):
+ self.this = apply(shapelibc.new_SHPObject,args)
+ self.thisown = 1
+
+ def __del__(self,shapelibc=shapelibc):
+ if self.thisown == 1 :
+ shapelibc.delete_SHPObject(self)
+ def extents(*args):
+ val = apply(shapelibc.SHPObject_extents,args)
+ return val
+ def vertices(*args):
+ val = apply(shapelibc.SHPObject_vertices,args)
+ return val
+ __setmethods__ = {
+ }
+ def __setattr__(self,name,value):
+ if (name == "this") or (name == "thisown"): self.__dict__[name] = value; return
+ method = SHPObject.__setmethods__.get(name,None)
+ if method: return method(self,value)
+ self.__dict__[name] = value
+ __getmethods__ = {
+ "type" : shapelibc.SHPObject_type_get,
+ "id" : shapelibc.SHPObject_id_get,
+ }
+ def __getattr__(self,name):
+ method = SHPObject.__getmethods__.get(name,None)
+ if method: return method(self)
+ raise AttributeError,name
+ def __repr__(self):
+ return "<C SHPObject instance at %s>" % (self.this,)
+class SHPObjectPtr(SHPObject):
+ def __init__(self,this):
+ self.this = this
+ self.thisown = 0
+ self.__class__ = SHPObject
+
+
+
+class ShapeFile:
+ def __init__(self,*args):
+ self.this = apply(shapelibc.new_ShapeFile,args)
+ self.thisown = 1
+
+ def __del__(self,shapelibc=shapelibc):
+ if self.thisown == 1 :
+ shapelibc.delete_ShapeFile(self)
+ def close(*args):
+ val = apply(shapelibc.ShapeFile_close,args)
+ return val
+ def info(*args):
+ val = apply(shapelibc.ShapeFile_info,args)
+ return val
+ def read_object(*args):
+ val = apply(shapelibc.ShapeFile_read_object,args)
+ if val: val = SHPObjectPtr(val) ; val.thisown = 1
+ return val
+ def write_object(*args):
+ val = apply(shapelibc.ShapeFile_write_object,args)
+ return val
+ def cobject(*args):
+ val = apply(shapelibc.ShapeFile_cobject,args)
+ return val
+ def __repr__(self):
+ return "<C ShapeFile instance at %s>" % (self.this,)
+class ShapeFilePtr(ShapeFile):
+ def __init__(self,this):
+ self.this = this
+ self.thisown = 0
+ self.__class__ = ShapeFile
+
+
+
+
+
+#-------------- FUNCTION WRAPPERS ------------------
+
+def open(*args, **kwargs):
+ val = apply(shapelibc.open,args,kwargs)
+ if val: val = ShapeFilePtr(val); val.thisown = 1
+ return val
+
+def create(*args, **kwargs):
+ val = apply(shapelibc.create,args,kwargs)
+ if val: val = ShapeFilePtr(val); val.thisown = 1
+ return val
+
+c_api = shapelibc.c_api
+
+type_name = shapelibc.type_name
+
+part_type_name = shapelibc.part_type_name
+
+
+
+#-------------- VARIABLE WRAPPERS ------------------
+
+SHPT_NULL = shapelibc.SHPT_NULL
+SHPT_POINT = shapelibc.SHPT_POINT
+SHPT_ARC = shapelibc.SHPT_ARC
+SHPT_POLYGON = shapelibc.SHPT_POLYGON
+SHPT_MULTIPOINT = shapelibc.SHPT_MULTIPOINT
+SHPT_POINTZ = shapelibc.SHPT_POINTZ
+SHPT_ARCZ = shapelibc.SHPT_ARCZ
+SHPT_POLYGONZ = shapelibc.SHPT_POLYGONZ
+SHPT_MULTIPOINTZ = shapelibc.SHPT_MULTIPOINTZ
+SHPT_POINTM = shapelibc.SHPT_POINTM
+SHPT_ARCM = shapelibc.SHPT_ARCM
+SHPT_POLYGONM = shapelibc.SHPT_POLYGONM
+SHPT_MULTIPOINTM = shapelibc.SHPT_MULTIPOINTM
+SHPT_MULTIPATCH = shapelibc.SHPT_MULTIPATCH
+SHPP_TRISTRIP = shapelibc.SHPP_TRISTRIP
+SHPP_TRIFAN = shapelibc.SHPP_TRIFAN
+SHPP_OUTERRING = shapelibc.SHPP_OUTERRING
+SHPP_INNERRING = shapelibc.SHPP_INNERRING
+SHPP_FIRSTRING = shapelibc.SHPP_FIRSTRING
+SHPP_RING = shapelibc.SHPP_RING
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib_wrap.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib_wrap.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/shapelib_wrap.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1411 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3u-20050630-1524 (Alpha 5)
+ *
+ * This file is not intended to be easily readable and contains a number of
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG
+ * interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPYTHON
+/***********************************************************************
+ * common.swg
+ *
+ * This file contains generic SWIG runtime support for pointer
+ * type checking as well as a few commonly used macros to control
+ * external linkage.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ *
+ * Copyright (c) 1999-2000, The University of Chicago
+ *
+ * This file may be freely redistributed without license or fee provided
+ * this copyright message remains intact.
+ ************************************************************************/
+
+#include <string.h>
+
+#if defined(_WIN32) || defined(__WIN32__)
+# if defined(_MSC_VER)
+# if defined(STATIC_LINKED)
+# define SWIGEXPORT(a) a
+# else
+# define SWIGEXPORT(a) __declspec(dllexport) a
+# endif
+# else
+# if defined(__BORLANDC__)
+# define SWIGEXPORT(a) a _export
+# else
+# define SWIGEXPORT(a) a
+# endif
+#endif
+#else
+# define SWIGEXPORT(a) a
+#endif
+
+#ifdef SWIG_GLOBAL
+#define SWIGRUNTIME(a) SWIGEXPORT(a)
+#else
+#define SWIGRUNTIME(a) static a
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct swig_type_info {
+ char *name;
+ void *(*converter)(void *);
+ char *str;
+ struct swig_type_info *next;
+ struct swig_type_info *prev;
+} swig_type_info;
+
+#ifdef SWIG_NOINCLUDE
+SWIGEXPORT(swig_type_info *) SWIG_TypeRegister(swig_type_info *);
+SWIGEXPORT(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *);
+SWIGEXPORT(void *) SWIG_TypeCast(swig_type_info *, void *);
+#else
+
+static swig_type_info *swig_type_list = 0;
+
+/* Register a type mapping with the type-checking */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeRegister(swig_type_info *ti)
+{
+ swig_type_info *tc, *head, *ret, *next;
+ /* Check to see if this type has already been registered */
+ tc = swig_type_list;
+ while (tc) {
+ if (strcmp(tc->name, ti->name) == 0) {
+ /* Already exists in the table. Just add additional types to the list */
+ head = tc;
+ next = tc->next;
+ goto l1;
+ }
+ tc = tc->prev;
+ }
+ head = ti;
+ next = 0;
+
+ /* Place in list */
+ ti->prev = swig_type_list;
+ swig_type_list = ti;
+
+ /* Build linked lists */
+ l1:
+ ret = head;
+ tc = ti + 1;
+ /* Patch up the rest of the links */
+ while (tc->name) {
+ head->next = tc;
+ tc->prev = head;
+ head = tc;
+ tc++;
+ }
+ head->next = next;
+ return ret;
+}
+
+/* Check the typename */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeCheck(char *c, swig_type_info *ty)
+{
+ swig_type_info *s;
+ if (!ty) return 0; /* Void pointer */
+ s = ty->next; /* First element always just a name */
+ while (s) {
+ if (strcmp(s->name,c) == 0) {
+ if (s == ty->next) return s;
+ /* Move s to the top of the linked list */
+ s->prev->next = s->next;
+ if (s->next) {
+ s->next->prev = s->prev;
+ }
+ /* Insert s as second element in the list */
+ s->next = ty->next;
+ if (ty->next) ty->next->prev = s;
+ ty->next = s;
+ return s;
+ }
+ s = s->next;
+ }
+ return 0;
+}
+
+/* Cast a pointer (needed for C++ inheritance */
+SWIGRUNTIME(void *)
+SWIG_TypeCast(swig_type_info *ty, void *ptr)
+{
+ if ((!ty) || (!ty->converter)) return ptr;
+ return (*ty->converter)(ptr);
+}
+
+/* Search for a swig_type_info structure */
+SWIGRUNTIME(void *)
+SWIG_TypeQuery(const char *name) {
+ swig_type_info *ty = swig_type_list;
+ while (ty) {
+ if (ty->str && (strcmp(name,ty->str) == 0)) return ty;
+ if (ty->name && (strcmp(name,ty->name) == 0)) return ty;
+ ty = ty->prev;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/***********************************************************************
+ * python.swg
+ *
+ * This file contains the runtime support for Python modules
+ * and includes code for managing global variables and pointer
+ * type checking.
+ *
+ * Author : David Beazley (beazley at cs.uchicago.edu)
+ ************************************************************************/
+
+#include <stdlib.h>
+#include "Python.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SWIG_PY_INT 1
+#define SWIG_PY_FLOAT 2
+#define SWIG_PY_STRING 3
+#define SWIG_PY_POINTER 4
+
+/* Constant information structure */
+typedef struct swig_const_info {
+ int type;
+ char *name;
+ long lvalue;
+ double dvalue;
+ void *pvalue;
+ swig_type_info **ptype;
+} swig_const_info;
+
+#ifdef SWIG_NOINCLUDE
+
+SWIGEXPORT(PyObject *) SWIG_newvarlink();
+SWIGEXPORT(void) SWIG_addvarlink(PyObject *, char *, PyObject *(*)(void), int (*)(PyObject *));
+SWIGEXPORT(int) SWIG_ConvertPtr(PyObject *, void **, swig_type_info *, int);
+SWIGEXPORT(void) SWIG_MakePtr(char *c, void *, swig_type_info *);
+SWIGEXPORT(PyObject *) SWIG_NewPointerObj(void *, swig_type_info *);
+SWIGEXPORT(void) SWIG_InstallConstants(PyObject *d, swig_const_info constants[]);
+
+#else
+
+/* -----------------------------------------------------------------------------
+ * global variable support code.
+ * ----------------------------------------------------------------------------- */
+
+typedef struct swig_globalvar {
+ char *name; /* Name of global variable */
+ PyObject *(*get_attr)(void); /* Return the current value */
+ int (*set_attr)(PyObject *); /* Set the value */
+ struct swig_globalvar *next;
+} swig_globalvar;
+
+typedef struct swig_varlinkobject {
+ PyObject_HEAD
+ swig_globalvar *vars;
+} swig_varlinkobject;
+
+static PyObject *
+swig_varlink_repr(swig_varlinkobject *v) {
+ v = v;
+ return PyString_FromString("<Global variables>");
+}
+
+static int
+swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) {
+ swig_globalvar *var;
+ flags = flags;
+ fprintf(fp,"Global variables { ");
+ for (var = v->vars; var; var=var->next) {
+ fprintf(fp,"%s", var->name);
+ if (var->next) fprintf(fp,", ");
+ }
+ fprintf(fp," }\n");
+ return 0;
+}
+
+static PyObject *
+swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->get_attr)();
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return NULL;
+}
+
+static int
+swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+ swig_globalvar *var = v->vars;
+ while (var) {
+ if (strcmp(var->name,n) == 0) {
+ return (*var->set_attr)(p);
+ }
+ var = var->next;
+ }
+ PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+ return 1;
+}
+
+statichere PyTypeObject varlinktype = {
+ PyObject_HEAD_INIT(0)
+ 0,
+ "swigvarlink", /* Type name */
+ sizeof(swig_varlinkobject), /* Basic size */
+ 0, /* Itemsize */
+ 0, /* Deallocator */
+ (printfunc) swig_varlink_print, /* Print */
+ (getattrfunc) swig_varlink_getattr, /* get attr */
+ (setattrfunc) swig_varlink_setattr, /* Set attr */
+ 0, /* tp_compare */
+ (reprfunc) swig_varlink_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_mapping*/
+ 0, /* tp_hash */
+};
+
+/* Create a variable linking object for use later */
+SWIGRUNTIME(PyObject *)
+SWIG_newvarlink(void) {
+ swig_varlinkobject *result = 0;
+ result = PyMem_NEW(swig_varlinkobject,1);
+ varlinktype.ob_type = &PyType_Type; /* Patch varlinktype into a PyType */
+ result->ob_type = &varlinktype;
+ result->vars = 0;
+ result->ob_refcnt = 0;
+ Py_XINCREF((PyObject *) result);
+ return ((PyObject*) result);
+}
+
+SWIGRUNTIME(void)
+SWIG_addvarlink(PyObject *p, char *name,
+ PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+ swig_varlinkobject *v;
+ swig_globalvar *gv;
+ v= (swig_varlinkobject *) p;
+ gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+ gv->name = (char *) malloc(strlen(name)+1);
+ strcpy(gv->name,name);
+ gv->get_attr = get_attr;
+ gv->set_attr = set_attr;
+ gv->next = v->vars;
+ v->vars = gv;
+}
+/* Convert a pointer value */
+SWIGRUNTIME(int)
+SWIG_ConvertPtr(PyObject *obj, void **ptr, swig_type_info *ty, int flags) {
+ unsigned long p;
+ register int d;
+ swig_type_info *tc;
+ char *c;
+ static PyObject *SWIG_this = 0;
+ int newref = 0;
+
+ if (!obj || (obj == Py_None)) {
+ *ptr = 0;
+ return 0;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ if (!(PyCObject_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyCObject_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ *ptr = PyCObject_AsVoidPtr(obj);
+ c = (char *) PyCObject_GetDesc(obj);
+ if (newref) Py_DECREF(obj);
+ goto cobject;
+#else
+ if (!(PyString_Check(obj))) {
+ if (!SWIG_this)
+ SWIG_this = PyString_InternFromString("this");
+ obj = PyObject_GetAttr(obj,SWIG_this);
+ newref = 1;
+ if (!obj) goto type_error;
+ if (!PyString_Check(obj)) {
+ Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c = PyString_AsString(obj);
+ p = 0;
+ /* Pointer values must start with leading underscore */
+ if (*c != '_') {
+ *ptr = (void *) 0;
+ if (strcmp(c,"NULL") == 0) {
+ if (newref) Py_DECREF(obj);
+ return 0;
+ } else {
+ if (newref) Py_DECREF(obj);
+ goto type_error;
+ }
+ }
+ c++;
+ /* Extract hex value from pointer */
+ while ((d = *c)) {
+ if ((d >= '0') && (d <= '9'))
+ p = (p << 4) + (d - '0');
+ else if ((d >= 'a') && (d <= 'f'))
+ p = (p << 4) + (d - ('a'-10));
+ else
+ break;
+ c++;
+ }
+ *ptr = (void *) p;
+ if (newref) Py_DECREF(obj);
+#endif
+
+#ifdef SWIG_COBJECT_TYPES
+cobject:
+#endif
+
+ if (ty) {
+ tc = SWIG_TypeCheck(c,ty);
+ if (!tc) goto type_error;
+ *ptr = SWIG_TypeCast(tc,(void*)p);
+ }
+ return 0;
+
+type_error:
+
+ if (flags) {
+ if (ty) {
+ char *temp = (char *) malloc(64+strlen(ty->name));
+ sprintf(temp,"Type error. Expected %s", ty->name);
+ PyErr_SetString(PyExc_TypeError, temp);
+ free((char *) temp);
+ } else {
+ PyErr_SetString(PyExc_TypeError,"Expected a pointer");
+ }
+ }
+ return -1;
+}
+
+/* Take a pointer and convert it to a string */
+SWIGRUNTIME(void)
+SWIG_MakePtr(char *c, void *ptr, swig_type_info *ty) {
+ static char hex[17] = "0123456789abcdef";
+ unsigned long p, s;
+ char result[32], *r;
+ r = result;
+ p = (unsigned long) ptr;
+ if (p > 0) {
+ while (p > 0) {
+ s = p & 0xf;
+ *(r++) = hex[s];
+ p = p >> 4;
+ }
+ *r = '_';
+ while (r >= result)
+ *(c++) = *(r--);
+ strcpy (c, ty->name);
+ } else {
+ strcpy (c, "NULL");
+ }
+}
+
+/* Create a new pointer object */
+SWIGRUNTIME(PyObject *)
+SWIG_NewPointerObj(void *ptr, swig_type_info *type) {
+ char result[512];
+ PyObject *robj;
+ if (!ptr) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+#ifdef SWIG_COBJECT_TYPES
+ robj = PyCObject_FromVoidPtrAndDesc((void *) ptr, type->name, NULL);
+#else
+ SWIG_MakePtr(result,ptr,type);
+ robj = PyString_FromString(result);
+#endif
+ return robj;
+}
+
+/* Install Constants */
+SWIGRUNTIME(void)
+SWIG_InstallConstants(PyObject *d, swig_const_info constants[]) {
+ int i;
+ PyObject *obj;
+ for (i = 0; constants[i].type; i++) {
+ switch(constants[i].type) {
+ case SWIG_PY_INT:
+ obj = PyInt_FromLong(constants[i].lvalue);
+ break;
+ case SWIG_PY_FLOAT:
+ obj = PyFloat_FromDouble(constants[i].dvalue);
+ break;
+ case SWIG_PY_STRING:
+ obj = PyString_FromString((char *) constants[i].pvalue);
+ break;
+ case SWIG_PY_POINTER:
+ obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype);
+ break;
+ default:
+ obj = 0;
+ break;
+ }
+ if (obj) {
+ PyDict_SetItemString(d,constants[i].name,obj);
+ Py_DECREF(obj);
+ }
+ }
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_ShapeFile swig_types[0]
+#define SWIGTYPE_p_SHPObject swig_types[1]
+static swig_type_info *swig_types[3];
+
+/* -------- TYPES TABLE (END) -------- */
+
+
+/*-----------------------------------------------
+ @(target):= shapelibc.so
+ ------------------------------------------------*/
+#define SWIG_init initshapelibc
+
+#define SWIG_name "shapelibc"
+
+
+/* import the shapelib headefile. */
+#include "shapefil.h"
+#include "pyshapelib_api.h"
+
+/*
+ * Rename a few shapelib functions that are effectively methods with
+ * preprocessor macros so that they have the names that swig expects
+ * (e.g. the destructor of SHPObject has to be called delete_SHPObject)
+ */
+
+#define delete_SHPObject SHPDestroyObject
+
+/*
+ * The extents() method of SHPObject.
+ *
+ * Return the extents as a tuple of two 4-element lists with the min.
+ * and max. values of x, y, z, m.
+ */
+static PyObject *
+SHPObject_extents(SHPObject *object)
+{
+ return Py_BuildValue("[dddd][dddd]",
+ object->dfXMin, object->dfYMin, object->dfZMin,
+ object->dfMMin,
+ object->dfXMax, object->dfYMax, object->dfZMax,
+ object->dfMMax);
+}
+
+
+/*
+ * The vertices() method of SHPObject.
+ *
+ * Return the x and y coords of the vertices as a list of lists of
+ * tuples.
+ */
+
+static PyObject* build_vertex_list(SHPObject *object, int index, int length);
+
+static PyObject*
+SHPObject_vertices(SHPObject *object)
+{
+ PyObject *result = NULL;
+ PyObject *part = NULL;
+ int part_idx, vertex_idx;
+ int length = 0;
+
+
+ if (object->nParts > 0)
+ {
+ /* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
+
+ result = PyList_New(object->nParts);
+ if (!result)
+ return NULL;
+
+ for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
+ part_idx++)
+ {
+ if (part_idx < object->nParts - 1)
+ length = (object->panPartStart[part_idx + 1]
+ - object->panPartStart[part_idx]);
+ else
+ length = object->nVertices - object->panPartStart[part_idx];
+
+ part = build_vertex_list(object, vertex_idx, length);
+ if (!part)
+ goto fail;
+
+ if (PyList_SetItem(result, part_idx, part) < 0)
+ goto fail;
+
+ vertex_idx += length;
+ }
+ }
+ else
+ {
+ /* only one part. usual for SHPT_POINT */
+ result = build_vertex_list(object, 0, object->nVertices);
+ }
+
+ return result;
+
+ fail:
+ Py_XDECREF(part);
+ Py_DECREF(result);
+ return NULL;
+}
+
+
+/* Return the length coordinates of the shape object starting at vertex
+ * index as a Python-list of tuples. Helper function for
+ * SHPObject_vertices.
+ */
+static PyObject*
+build_vertex_list(SHPObject *object, int index, int length)
+{
+ int i;
+ PyObject * list;
+ PyObject * vertex = NULL;
+
+ list = PyList_New(length);
+ if (!list)
+ return NULL;
+
+ for (i = 0; i < length; i++, index++)
+ {
+ vertex = Py_BuildValue("dd", object->padfX[index],
+ object->padfY[index]);
+ if (!vertex)
+ goto fail;
+ if (PyList_SetItem(list, i, vertex) < 0)
+ goto fail;
+ }
+
+ return list;
+
+ fail:
+ Py_XDECREF(vertex);
+ Py_DECREF(list);
+ return NULL;
+}
+
+
+
+
+
+/* The constructor of SHPObject. parts is a list of lists of tuples
+ * describing the parts and their vertices just likethe output of the
+ * vertices() method. part_type_list is the list of part-types and may
+ * be NULL. For the meaning of the part-types and their default value
+ * see the Shaplib documentation.
+ */
+SHPObject * new_SHPObject(int type, int id, PyObject * parts,
+ PyObject * part_type_list)
+{
+ /* arrays to hold thex and y coordinates of the vertices */
+ double *xs = NULL, *ys = NULL;
+ /* number of all vertices of all parts */
+ int num_vertices;
+ /* number of parts in the list parts */
+ int num_parts;
+ /* start index of in xs and ys of the part currently worked on */
+ int part_start;
+ /* array of start indices in xs and ys as expected by shapelib */
+ int *part_starts = NULL;
+
+ /* generic counter */
+ int i;
+
+ /* array of part types. holds the converted content of
+ * part_type_list. Stays NULL of part_type_list is NULL
+ */
+ int *part_types = NULL;
+
+ /* temporary python objects referring to the the list items being
+ * worked on.
+ */
+ PyObject * part = NULL, *tuple = NULL;
+
+ /* The result object */
+ SHPObject *result;
+
+ num_parts = PySequence_Length(parts);
+ num_vertices = 0;
+
+ /* parts and part_types have to have the same lengths */
+ if (part_type_list
+ && PySequence_Length(parts) != PySequence_Length(part_type_list))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "parts and part_types have to have the same lengths");
+ return NULL;
+ }
+
+ /* determine how many vertices there are altogether */
+ for (i = 0; i < num_parts; i++)
+ {
+ PyObject * part = PySequence_GetItem(parts, i);
+ if (!part)
+ return NULL;
+ num_vertices += PySequence_Length(part);
+ Py_DECREF(part);
+ }
+
+ /* allocate the memory for the various arrays and check for memory
+ errors */
+ xs = malloc(num_vertices * sizeof(double));
+ ys = malloc(num_vertices * sizeof(double));
+ part_starts = malloc(num_parts * sizeof(int));
+ if (part_type_list)
+ part_types = malloc(num_parts * sizeof(int));
+
+ if (!xs || !ys || !part_starts || (part_type_list && !part_types))
+ {
+ PyErr_NoMemory();
+ goto fail;
+ }
+
+ /* convert the part types */
+ if (part_type_list)
+ {
+ for (i = 0; i < num_parts; i++)
+ {
+ PyObject * otype = PySequence_GetItem(part_type_list, i);
+ if (!otype)
+ return NULL;
+ part_types[i] = PyInt_AsLong(otype);
+ Py_DECREF(otype);
+ }
+ }
+
+ /* convert the list of parts */
+ part_start = 0;
+ for (i = 0; i < num_parts; i++)
+ {
+ int j, length;
+
+ part = PySequence_GetItem(parts, i);
+ length = PySequence_Length(part);
+ part_starts[i] = part_start;
+
+ for (j = 0; j < length; j++)
+ {
+ tuple = PySequence_GetItem(part, j);
+ if (!tuple)
+ goto fail;
+
+ if (!PyArg_ParseTuple(tuple, "dd", xs + part_start + j,
+ ys + part_start + j))
+ {
+ goto fail;
+ }
+ Py_DECREF(tuple);
+ tuple = NULL;
+ }
+ Py_DECREF(part);
+ part = NULL;
+ part_start += length;
+ }
+
+ result = SHPCreateObject(type, id, num_parts, part_starts, part_types,
+ num_vertices, xs, ys, NULL, NULL);
+ free(xs);
+ free(ys);
+ free(part_starts);
+ free(part_types);
+ return result;
+
+ fail:
+ free(xs);
+ free(ys);
+ free(part_starts);
+ free(part_types);
+ Py_XDECREF(part);
+ Py_XDECREF(tuple);
+ return NULL;
+}
+
+
+static PyObject* l_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyList_Check(target)) {
+ o2 = target;
+ target = PyList_New(0);
+ PyList_Append(target, o2);
+ Py_XDECREF(o2);
+ }
+ PyList_Append(target,o);
+ Py_XDECREF(o);
+ }
+ return target;
+}
+
+static PyObject* t_output_helper(PyObject* target, PyObject* o) {
+ PyObject* o2;
+ PyObject* o3;
+
+ if (!target) {
+ target = o;
+ } else if (target == Py_None) {
+ Py_DECREF(Py_None);
+ target = o;
+ } else {
+ if (!PyTuple_Check(target)) {
+ o2 = target;
+ target = PyTuple_New(1);
+ PyTuple_SetItem(target, 0, o2);
+ }
+ o3 = PyTuple_New(1);
+ PyTuple_SetItem(o3, 0, o);
+
+ o2 = target;
+ target = PySequence_Concat(o2, o3);
+ Py_DECREF(o2);
+ Py_DECREF(o3);
+ }
+ return target;
+}
+
+#define SWIG_MemoryError 1
+#define SWIG_IOError 2
+#define SWIG_RuntimeError 3
+#define SWIG_IndexError 4
+#define SWIG_TypeError 5
+#define SWIG_DivisionByZero 6
+#define SWIG_OverflowError 7
+#define SWIG_SyntaxError 8
+#define SWIG_ValueError 9
+#define SWIG_SystemError 10
+#define SWIG_UnknownError 99
+
+static void _SWIG_exception(int code, char *msg) {
+ switch(code) {
+ case SWIG_MemoryError:
+ PyErr_SetString(PyExc_MemoryError,msg);
+ break;
+ case SWIG_IOError:
+ PyErr_SetString(PyExc_IOError,msg);
+ break;
+ case SWIG_RuntimeError:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ case SWIG_IndexError:
+ PyErr_SetString(PyExc_IndexError,msg);
+ break;
+ case SWIG_TypeError:
+ PyErr_SetString(PyExc_TypeError,msg);
+ break;
+ case SWIG_DivisionByZero:
+ PyErr_SetString(PyExc_ZeroDivisionError,msg);
+ break;
+ case SWIG_OverflowError:
+ PyErr_SetString(PyExc_OverflowError,msg);
+ break;
+ case SWIG_SyntaxError:
+ PyErr_SetString(PyExc_SyntaxError,msg);
+ break;
+ case SWIG_ValueError:
+ PyErr_SetString(PyExc_ValueError,msg);
+ break;
+ case SWIG_SystemError:
+ PyErr_SetString(PyExc_SystemError,msg);
+ break;
+ default:
+ PyErr_SetString(PyExc_RuntimeError,msg);
+ break;
+ }
+}
+
+#define SWIG_exception(a,b) { _SWIG_exception(a,b); return NULL; }
+
+ typedef struct {
+ SHPHandle handle;
+ } ShapeFile;
+
+#define NOCHECK_delete_ShapeFile
+#define NOCHECK_ShapeFile_close
+
+ ShapeFile * open_ShapeFile(const char *filename, const char * mode) {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPOpen(filename, mode);
+ return self;
+ }
+
+ ShapeFile * create_ShapeFile(const char *filename, int type) {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPCreate(filename, type);
+ return self;
+ }
+
+ static PyShapeLibAPI the_api = {
+ SHPReadObject,
+ SHPDestroyObject,
+ SHPCreateTree,
+ SHPDestroyTree,
+ SHPTreeFindLikelyShapes
+ };
+
+ PyObject * c_api() {
+ return PyCObject_FromVoidPtr(&the_api, NULL);
+ }
+#ifdef __cplusplus
+extern "C" {
+#endif
+static PyObject *_wrap_open(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ char *arg1 = "rb" ;
+ ShapeFile *result ;
+
+ if(!PyArg_ParseTuple(args,"s|s:open",&arg0,&arg1)) return NULL;
+ {
+ result = (ShapeFile *)open_ShapeFile((char const *)arg0,(char const *)arg1);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "open_ShapeFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_ShapeFile);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_create(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ int arg1 ;
+ ShapeFile *result ;
+
+ if(!PyArg_ParseTuple(args,"si:create",&arg0,&arg1)) return NULL;
+ {
+ result = (ShapeFile *)create_ShapeFile((char const *)arg0,arg1);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "create_ShapeFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_ShapeFile);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_c_api(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,":c_api")) return NULL;
+ result = (PyObject *)c_api();
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_type_name(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ char *result ;
+
+ if(!PyArg_ParseTuple(args,"i:type_name",&arg0)) return NULL;
+ result = (char *)SHPTypeName(arg0);
+ resultobj = PyString_FromString(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_part_type_name(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ char *result ;
+
+ if(!PyArg_ParseTuple(args,"i:part_type_name",&arg0)) return NULL;
+ result = (char *)SHPPartTypeName(arg0);
+ resultobj = PyString_FromString(result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_SHPObject_type_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ SHPObject *arg0 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"O:SHPObject_type_get",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ result = (int ) (arg0->nSHPType);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_SHPObject_id_get(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ SHPObject *arg0 ;
+ PyObject * argo0 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"O:SHPObject_id_get",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ result = (int ) (arg0->nShapeId);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_new_SHPObject(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ int arg0 ;
+ int arg1 ;
+ PyObject *arg2 ;
+ PyObject *arg3 = NULL ;
+ PyObject * obj2 = 0 ;
+ PyObject * obj3 = 0 ;
+ SHPObject *result ;
+
+ if(!PyArg_ParseTuple(args,"iiO|O:new_SHPObject",&arg0,&arg1,&obj2,&obj3)) return NULL;
+ {
+ arg2 = obj2;
+ }
+ if (obj3)
+ {
+ arg3 = obj3;
+ }
+ {
+ result = (SHPObject *)new_SHPObject(arg0,arg1,arg2,arg3);
+ ;
+ if (PyErr_Occurred())
+ return NULL;
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_SHPObject);
+ return resultobj;
+}
+
+
+static PyObject *_wrap_delete_SHPObject(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ SHPObject *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:delete_SHPObject",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ delete_SHPObject(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+static PyObject *_wrap_SHPObject_extents(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ SHPObject *arg0 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"O:SHPObject_extents",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ result = (PyObject *)SHPObject_extents(arg0);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+static PyObject *_wrap_SHPObject_vertices(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ SHPObject *arg0 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"O:SHPObject_vertices",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ result = (PyObject *)SHPObject_vertices(arg0);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+ShapeFile * new_ShapeFile(char *file,char *mode) {
+ {
+ ShapeFile * self = malloc(sizeof(ShapeFile));
+ if (self)
+ self->handle = SHPOpen(file, mode);
+ return self;
+ }
+}
+
+
+static PyObject *_wrap_new_ShapeFile(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ char *arg0 ;
+ char *arg1 = "rb" ;
+ ShapeFile *result ;
+
+ if(!PyArg_ParseTuple(args,"s|s:new_ShapeFile",&arg0,&arg1)) return NULL;
+ {
+ result = (ShapeFile *)new_ShapeFile(arg0,arg1);
+ ;
+ if (!result)
+ {
+ SWIG_exception(SWIG_MemoryError, "no memory");
+ }
+ else if (!result->handle)
+ {
+ SWIG_exception(SWIG_IOError, "new_ShapeFile failed");
+ }
+ }resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_ShapeFile);
+ return resultobj;
+}
+
+
+void delete_ShapeFile(ShapeFile *self) {
+ {
+ if (self->handle)
+ SHPClose(self->handle);
+ free(self);
+ }
+}
+
+
+static PyObject *_wrap_delete_ShapeFile(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:delete_ShapeFile",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_delete_ShapeFile
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ delete_ShapeFile(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+void ShapeFile_close(ShapeFile *self) {
+ {
+ if (self->handle)
+ {
+ SHPClose(self->handle);
+ self->handle = NULL;
+ }
+ }
+}
+
+
+static PyObject *_wrap_ShapeFile_close(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ PyObject * argo0 =0 ;
+
+ if(!PyArg_ParseTuple(args,"O:ShapeFile_close",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_ShapeFile_close
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ ShapeFile_close(arg0);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ return resultobj;
+}
+
+
+void ShapeFile_info(ShapeFile *self,int *output_entities,int *output_type,double *output_min_bounds,double *output_max_bounds) {
+ {
+ SHPGetInfo(self->handle, output_entities, output_type,
+ output_min_bounds, output_max_bounds);
+ }
+}
+
+
+static PyObject *_wrap_ShapeFile_info(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ int *arg1 ;
+ int *arg2 ;
+ double *arg3 ;
+ double *arg4 ;
+ int temp ;
+ int temp0 ;
+ double temp1[4] ;
+ double temp2[4] ;
+ PyObject * argo0 =0 ;
+
+ {
+ arg1 = &temp;
+ }
+ {
+ arg2 = &temp0;
+ }
+ {
+ arg3 = temp1;
+ }
+ {
+ arg4 = temp2;
+ }
+ if(!PyArg_ParseTuple(args,"O:ShapeFile_info",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_ShapeFile_info
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ ShapeFile_info(arg0,arg1,arg2,arg3,arg4);
+ Py_INCREF(Py_None);
+ resultobj = Py_None;
+ {
+ PyObject *o;
+ o = PyInt_FromLong((long) (*arg1));
+ resultobj = t_output_helper(resultobj, o);
+ }
+ {
+ PyObject *o;
+ o = PyInt_FromLong((long) (*arg2));
+ resultobj = t_output_helper(resultobj, o);
+ }
+ {
+ PyObject * list = Py_BuildValue("[dddd]",
+ arg3[0], arg3[1],
+ arg3[2], arg3[3]);
+ resultobj = t_output_helper(resultobj,list);
+ }
+ {
+ PyObject * list = Py_BuildValue("[dddd]",
+ arg4[0], arg4[1],
+ arg4[2], arg4[3]);
+ resultobj = t_output_helper(resultobj,list);
+ }
+ return resultobj;
+}
+
+
+SHPObject * ShapeFile_read_object(ShapeFile *self,int i) {
+ {
+ return SHPReadObject(self->handle, i);
+ }
+}
+
+
+static PyObject *_wrap_ShapeFile_read_object(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ int arg1 ;
+ PyObject * argo0 =0 ;
+ SHPObject *result ;
+
+ if(!PyArg_ParseTuple(args,"Oi:ShapeFile_read_object",&argo0,&arg1)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_ShapeFile_read_object
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ result = (SHPObject *)ShapeFile_read_object(arg0,arg1);
+ resultobj = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_SHPObject);
+ return resultobj;
+}
+
+
+int ShapeFile_write_object(ShapeFile *self,int iShape,SHPObject *psObject) {
+ {
+ return SHPWriteObject(self->handle, iShape, psObject);
+ }
+}
+
+
+static PyObject *_wrap_ShapeFile_write_object(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ int arg1 ;
+ SHPObject *arg2 ;
+ PyObject * argo0 =0 ;
+ PyObject * argo2 =0 ;
+ int result ;
+
+ if(!PyArg_ParseTuple(args,"OiO:ShapeFile_write_object",&argo0,&arg1,&argo2)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ if ((SWIG_ConvertPtr(argo2,(void **) &arg2,SWIGTYPE_p_SHPObject,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_ShapeFile_write_object
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ result = (int )ShapeFile_write_object(arg0,arg1,arg2);
+ resultobj = PyInt_FromLong((long)result);
+ return resultobj;
+}
+
+
+PyObject * ShapeFile_cobject(ShapeFile *self) {
+ {
+ return PyCObject_FromVoidPtr(self->handle, NULL);
+ }
+}
+
+
+static PyObject *_wrap_ShapeFile_cobject(PyObject *self, PyObject *args) {
+ PyObject *resultobj;
+ ShapeFile *arg0 ;
+ PyObject * argo0 =0 ;
+ PyObject *result ;
+
+ if(!PyArg_ParseTuple(args,"O:ShapeFile_cobject",&argo0)) return NULL;
+ if ((SWIG_ConvertPtr(argo0,(void **) &arg0,SWIGTYPE_p_ShapeFile,1)) == -1) return NULL;
+ {
+ #ifndef NOCHECK_ShapeFile_cobject
+ if (!arg0 || !arg0->handle)
+ SWIG_exception(SWIG_TypeError, "shapefile already closed");
+ #endif
+ }
+ result = (PyObject *)ShapeFile_cobject(arg0);
+ {
+ resultobj = result;
+ }
+ return resultobj;
+}
+
+
+static PyMethodDef shapelibcMethods[] = {
+ { "open", _wrap_open, METH_VARARGS },
+ { "create", _wrap_create, METH_VARARGS },
+ { "c_api", _wrap_c_api, METH_VARARGS },
+ { "type_name", _wrap_type_name, METH_VARARGS },
+ { "part_type_name", _wrap_part_type_name, METH_VARARGS },
+ { "SHPObject_type_get", _wrap_SHPObject_type_get, METH_VARARGS },
+ { "SHPObject_id_get", _wrap_SHPObject_id_get, METH_VARARGS },
+ { "new_SHPObject", _wrap_new_SHPObject, METH_VARARGS },
+ { "delete_SHPObject", _wrap_delete_SHPObject, METH_VARARGS },
+ { "SHPObject_extents", _wrap_SHPObject_extents, METH_VARARGS },
+ { "SHPObject_vertices", _wrap_SHPObject_vertices, METH_VARARGS },
+ { "new_ShapeFile", _wrap_new_ShapeFile, METH_VARARGS },
+ { "delete_ShapeFile", _wrap_delete_ShapeFile, METH_VARARGS },
+ { "ShapeFile_close", _wrap_ShapeFile_close, METH_VARARGS },
+ { "ShapeFile_info", _wrap_ShapeFile_info, METH_VARARGS },
+ { "ShapeFile_read_object", _wrap_ShapeFile_read_object, METH_VARARGS },
+ { "ShapeFile_write_object", _wrap_ShapeFile_write_object, METH_VARARGS },
+ { "ShapeFile_cobject", _wrap_ShapeFile_cobject, METH_VARARGS },
+ { NULL, NULL }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_ShapeFile[] = {{"_p_ShapeFile", 0, "ShapeFile *"},{"_p_ShapeFile"},{0}};
+static swig_type_info _swigt__p_SHPObject[] = {{"_p_SHPObject", 0, "SHPObject *"},{"_p_SHPObject"},{0}};
+
+static swig_type_info *swig_types_initial[] = {
+_swigt__p_ShapeFile,
+_swigt__p_SHPObject,
+0
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+ { SWIG_PY_INT, "SHPT_NULL", (long) 0, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POINT", (long) 1, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_ARC", (long) 3, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POLYGON", (long) 5, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_MULTIPOINT", (long) 8, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POINTZ", (long) 11, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_ARCZ", (long) 13, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POLYGONZ", (long) 15, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_MULTIPOINTZ", (long) 18, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POINTM", (long) 21, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_ARCM", (long) 23, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_POLYGONM", (long) 25, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_MULTIPOINTM", (long) 28, 0, 0, 0},
+ { SWIG_PY_INT, "SHPT_MULTIPATCH", (long) 31, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_TRISTRIP", (long) 0, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_TRIFAN", (long) 1, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_OUTERRING", (long) 2, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_INNERRING", (long) 3, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_FIRSTRING", (long) 4, 0, 0, 0},
+ { SWIG_PY_INT, "SHPP_RING", (long) 5, 0, 0, 0},
+{0}};
+
+static PyObject *SWIG_globals;
+#ifdef __cplusplus
+extern "C"
+#endif
+SWIGEXPORT(void) initshapelibc(void) {
+ PyObject *m, *d;
+ int i;
+ SWIG_globals = SWIG_newvarlink();
+ m = Py_InitModule("shapelibc", shapelibcMethods);
+ d = PyModule_GetDict(m);
+ for (i = 0; swig_types_initial[i]; i++) {
+ swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);
+ }
+ SWIG_InstallConstants(d,swig_const_table);
+}
+
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/shptreemodule.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/shptreemodule.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/shptreemodule.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,176 @@
+/* Copyright (c) 2001, 2002 by Intevation GmbH
+ * Authors:
+ * Bernhard Herzog <bh at intevation.de>
+ *
+ * This program is free software under the GPL (>=v2)
+ * Read the file COPYING coming with Thuban for details.
+ */
+
+/* Python wrapper for the shapelib SHPTree */
+
+#include <Python.h>
+#include <shapefil.h>
+
+#include "pyshapelib_api.h"
+
+PyShapeLibAPI * api;
+
+typedef struct {
+ PyObject_HEAD
+ SHPTree * tree;
+} SHPTreeObject;
+
+extern PyTypeObject SHPTreeType;
+
+#define SHPTree_Check(v) ((v)->ob_type == &SHPTreeType)
+
+/* Create a new python wrapper object from a SHPTree pointer */
+static PyObject *
+SHPTreeObject_FromSHPTree(SHPTree* tree)
+{
+ SHPTreeObject * self = PyObject_NEW(SHPTreeObject, &SHPTreeType);
+ if (!self)
+ return NULL;
+
+ self->tree = tree;
+
+ return (PyObject *)self;
+}
+
+/* Deallocate the SHPTree wrapper. */
+static void
+shptree_dealloc(SHPTreeObject * self)
+{
+ api->SHPDestroyTree(self->tree);
+ PyMem_DEL(self);
+}
+
+/* Return the repr of the wrapper */
+static PyObject *
+shptree_repr(SHPTreeObject * self)
+{
+ char buf[1000];
+ sprintf(buf, "<SHPTree at %xul>", (unsigned long)self);
+ return PyString_FromString(buf);
+}
+
+static PyObject *
+shptree_find_shapes(SHPTreeObject * self, PyObject * args)
+{
+ double min[4] = {0, 0, 0, 0};
+ double max[4] = {0, 0, 0, 0};
+ int count, idx;
+ int * ids;
+ PyObject * list = NULL, *temp = NULL;
+
+ if (!PyArg_ParseTuple(args, "(dd)(dd)", min + 0, min + 1,
+ max + 0, max + 1))
+ return NULL;
+
+ ids = api->SHPTreeFindLikelyShapes(self->tree, min, max, &count);
+
+ list = PyList_New(count);
+ if (!list)
+ goto fail;
+
+ /* Turn the returned array of indices into a python list of ints. */
+ for (idx = 0; idx < count; idx++)
+ {
+ temp = PyInt_FromLong(ids[idx]);
+ if (!temp)
+ goto fail;
+
+ if (PyList_SetItem(list, idx, temp) == -1)
+ {
+ /* temp's refcount has already be decreased. Set temp to
+ * NULL so that the fail code doesn't do it again
+ */
+ temp = NULL;
+ goto fail;
+ }
+ }
+
+ free(ids);
+ return list;
+
+ fail:
+ free(ids);
+ Py_XDECREF(list);
+ Py_XDECREF(temp);
+ return NULL;
+}
+
+
+static struct PyMethodDef shptree_methods[] = {
+ {"find_shapes", (PyCFunction)shptree_find_shapes, METH_VARARGS},
+ {NULL, NULL}
+};
+
+static PyObject *
+shptree_getattr(PyObject * self, char * name)
+{
+ return Py_FindMethod(shptree_methods, self, name);
+}
+
+
+PyTypeObject SHPTreeType = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "SHPTree",
+ sizeof(SHPTreeObject),
+ 0,
+ (destructor)shptree_dealloc, /*tp_dealloc*/
+ (printfunc)NULL, /*tp_print*/
+ shptree_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)shptree_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+};
+
+
+
+static PyObject *
+shptree_from_shapefile(PyObject * self, PyObject * args)
+{
+ SHPTree * tree;
+ SHPHandle handle;
+ PyObject * cobject;
+ int dimension, max_depth;
+
+ if (!PyArg_ParseTuple(args, "O!ii", &PyCObject_Type, &cobject,
+ &dimension, &max_depth))
+ return NULL;
+
+ handle = PyCObject_AsVoidPtr(cobject);
+
+ tree = api->SHPCreateTree(handle, dimension, max_depth, NULL, NULL);
+
+ /* apparently SHPCreateTree doesn't do any error checking, so we
+ * have to assume that tree is valid at this point. */
+ return SHPTreeObject_FromSHPTree(tree);
+}
+
+
+static PyMethodDef module_functions[] = {
+ {"SHPTree", shptree_from_shapefile, METH_VARARGS},
+ { NULL, NULL }
+};
+
+
+void
+initshptree()
+{
+ SHPTreeType.ob_type = &PyType_Type;
+
+ Py_InitModule("shptree", module_functions);
+ PYSHAPELIB_IMPORT_API(api);
+}
Added: packages/thuban/branches/upstream/current/libraries/pyshapelib/testdbf.py
===================================================================
--- packages/thuban/branches/upstream/current/libraries/pyshapelib/testdbf.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/pyshapelib/testdbf.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,28 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the LGPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test cases for the dbflib python bindings"""
+
+__version__ = "$Revision: 1762 $"
+# $Source$
+# $Id: testdbf.py 1762 2003-09-29 10:52:38Z bh $
+
+import unittest
+import dbflib
+
+class TestDBF(unittest.TestCase):
+
+ def test_add_field(self):
+ """Test whethe add_field reports exceptions"""
+ dbf = dbflib.create("test.dbf")
+ # For strings the precision parameter must be 0
+ self.assertRaises(RuntimeError,
+ dbf.add_field, "str", dbflib.FTString, 10, 5)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/libraries/shapelib/dbfopen.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/shapelib/dbfopen.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/shapelib/dbfopen.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1594 @@
+/******************************************************************************
+ * $Id: dbfopen.c 2703 2006-09-24 18:51:39Z bernhard $
+ *
+ * Project: Shapelib
+ * Purpose: Implementation of .dbf access API documented in dbf_api.html.
+ * Author: Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * This software is available under the following "MIT Style" license,
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * option is discussed in more detail in shapelib.html.
+ *
+ * --
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log$
+ * Revision 1.3 2004/05/17 15:47:57 bh
+ * Update to newest shapelib and get rid of Thuban specific extensions,
+ * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ *
+ * * libraries/shapelib/shpopen.c: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/shapefil.h: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/dbfopen.c: Update to version from current
+ * shapelib CVS.
+ * (DBFCommit): Effectively removed since shapelib itself has
+ * DBFUpdateHeader now which is better for what DBFCommit wanted to
+ * achieve.
+ * We're now using an unmodified version of dbfopen.
+ *
+ * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
+ * Update from dbflib.i
+ *
+ * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
+ * the commit method. This new indirection is necessary because we use the
+ * DBFUpdateHeader function now which is not available in shapelib <=
+ * 1.2.10
+ * (DBFFile::commit): Use DBFInfo_commit as implementation
+ * (pragma __class__): New. Kludge to remove the commit method when
+ * the DBFUpdateHeader function isn't available
+ * (_have_commit): New. Helper for the pragma kludge.
+ *
+ * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
+ * preprocessor macros needed to compile the dbflib wrapper. Determine
+ * whether DBFUpdateHeader is available and define the right value of
+ * HAVE_UPDATE_HEADER
+ * (extensions): Use dbf_macros for the dbflibc extension
+ *
+ * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
+ * value '1' to the Lib.dbflibc extension. This simply reflects the
+ * shapelib and pyshapelib updates
+ *
+ * Revision 1.53 2003/12/29 00:00:30 fwarmerdam
+ * mark DBFWriteAttributeDirectly as SHPAPI_CALL
+ *
+ * Revision 1.52 2003/07/08 15:20:03 warmerda
+ * avoid warnings about downcasting to unsigned char
+ *
+ * Revision 1.51 2003/07/08 13:50:15 warmerda
+ * DBFIsAttributeNULL check for pszValue==NULL - bug 360
+ *
+ * Revision 1.50 2003/04/21 18:58:25 warmerda
+ * ensure current record is flushed at same time as header is updated
+ *
+ * Revision 1.49 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.48 2003/03/10 14:51:27 warmerda
+ * DBFWrite* calls now return FALSE if they have to truncate
+ *
+ * Revision 1.47 2002/11/20 03:32:22 warmerda
+ * Ensure field name in DBFGetFieldIndex() is properly terminated.
+ *
+ * Revision 1.46 2002/10/09 13:10:21 warmerda
+ * Added check that width is positive.
+ *
+ * Revision 1.45 2002/09/29 00:00:08 warmerda
+ * added FTLogical and logical attribute read/write calls
+ *
+ * Revision 1.44 2002/05/07 13:46:11 warmerda
+ * Added DBFWriteAttributeDirectly().
+ *
+ * Revision 1.43 2002/02/13 19:39:21 warmerda
+ * Fix casting issues in DBFCloneEmpty().
+ *
+ * Revision 1.42 2002/01/15 14:36:07 warmerda
+ * updated email address
+ *
+ * Revision 1.41 2002/01/15 14:31:49 warmerda
+ * compute rather than copying nHeaderLength in DBFCloneEmpty()
+ *
+ * Revision 1.40 2002/01/09 04:32:35 warmerda
+ * fixed to read correct amount of header
+ *
+ * Revision 1.39 2001/12/11 22:41:03 warmerda
+ * improve io related error checking when reading header
+ *
+ * Revision 1.38 2001/11/28 16:07:31 warmerda
+ * Cleanup to avoid compiler warnings as suggested by Richard Hash.
+ *
+ * Revision 1.37 2001/07/04 05:18:09 warmerda
+ * do last fix properly
+ *
+ * Revision 1.36 2001/07/04 05:16:09 warmerda
+ * fixed fieldname comparison in DBFGetFieldIndex
+ *
+ * Revision 1.35 2001/06/22 02:10:06 warmerda
+ * fixed NULL shape support with help from Jim Matthews
+ *
+ * Revision 1.33 2001/05/31 19:20:13 warmerda
+ * added DBFGetFieldIndex()
+ *
+ * Revision 1.32 2001/05/31 18:15:40 warmerda
+ * Added support for NULL fields in DBF files
+ *
+ * Revision 1.31 2001/05/23 13:36:52 warmerda
+ * added use of SHPAPI_CALL
+ *
+ * Revision 1.30 2000/12/05 14:43:38 warmerda
+ * DBReadAttribute() white space trimming bug fix
+ *
+ * Revision 1.29 2000/10/05 14:36:44 warmerda
+ * fix bug with writing very wide numeric fields
+ *
+ * Revision 1.28 2000/09/25 14:18:07 warmerda
+ * Added some casts of strlen() return result to fix warnings on some
+ * systems, as submitted by Daniel.
+ *
+ * Revision 1.27 2000/09/25 14:15:51 warmerda
+ * added DBFGetNativeFieldType()
+ *
+ * Revision 1.26 2000/07/07 13:39:45 warmerda
+ * removed unused variables, and added system include files
+ *
+ * Revision 1.25 2000/05/29 18:19:13 warmerda
+ * avoid use of uchar, and adding casting fix
+ *
+ * Revision 1.24 2000/05/23 13:38:27 warmerda
+ * Added error checks on return results of fread() and fseek().
+ *
+ * Revision 1.23 2000/05/23 13:25:49 warmerda
+ * Avoid crashing if field or record are out of range in dbfread*attribute().
+ *
+ * Revision 1.22 1999/12/15 13:47:24 warmerda
+ * Added stdlib.h to ensure that atof() is prototyped.
+ *
+ * Revision 1.21 1999/12/13 17:25:46 warmerda
+ * Added support for upper case .DBF extention.
+ *
+ * Revision 1.20 1999/11/30 16:32:11 warmerda
+ * Use atof() instead of sscanf().
+ *
+ * Revision 1.19 1999/11/05 14:12:04 warmerda
+ * updated license terms
+ *
+ * Revision 1.18 1999/07/27 00:53:28 warmerda
+ * ensure that whole old field value clear on write of string
+ *
+ * Revision 1.1 1999/07/05 18:58:07 warmerda
+ * New
+ *
+ * Revision 1.17 1999/06/11 19:14:12 warmerda
+ * Fixed some memory leaks.
+ *
+ * Revision 1.16 1999/06/11 19:04:11 warmerda
+ * Remoted some unused variables.
+ *
+ * Revision 1.15 1999/05/11 03:19:28 warmerda
+ * added new Tuple api, and improved extension handling - add from candrsn
+ *
+ * Revision 1.14 1999/05/04 15:01:48 warmerda
+ * Added 'F' support.
+ *
+ * Revision 1.13 1999/03/23 17:38:59 warmerda
+ * DBFAddField() now actually does return the new field number, or -1 if
+ * it fails.
+ *
+ * Revision 1.12 1999/03/06 02:54:46 warmerda
+ * Added logic to convert shapefile name to dbf filename in DBFOpen()
+ * for convenience.
+ *
+ * Revision 1.11 1998/12/31 15:30:34 warmerda
+ * Improved the interchangability of numeric and string attributes. Add
+ * white space trimming option for attributes.
+ *
+ * Revision 1.10 1998/12/03 16:36:44 warmerda
+ * Use r+b instead of rb+ for binary access.
+ *
+ * Revision 1.9 1998/12/03 15:34:23 warmerda
+ * Updated copyright message.
+ *
+ * Revision 1.8 1997/12/04 15:40:15 warmerda
+ * Added newline character after field definitions.
+ *
+ * Revision 1.7 1997/03/06 14:02:10 warmerda
+ * Ensure bUpdated is initialized.
+ *
+ * Revision 1.6 1996/02/12 04:54:41 warmerda
+ * Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
+ *
+ * Revision 1.5 1995/10/21 03:15:12 warmerda
+ * Changed to use binary file access, and ensure that the
+ * field name field is zero filled, and limited to 10 chars.
+ *
+ * Revision 1.4 1995/08/24 18:10:42 warmerda
+ * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
+ * as on the Sun.
+ *
+ * Revision 1.3 1995/08/04 03:15:16 warmerda
+ * Fixed up header.
+ *
+ * Revision 1.2 1995/08/04 03:14:43 warmerda
+ * Added header.
+ */
+
+static char rcsid[] =
+ "$Id: dbfopen.c 2703 2006-09-24 18:51:39Z bernhard $";
+
+#include "shapefil.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE 1
+#endif
+
+static int nStringFieldLen = 0;
+static char * pszStringField = NULL;
+
+/************************************************************************/
+/* DBFSet_atof_function() */
+/* */
+/* This makes it possible to initialise a different atof() function */
+/* which might be necessary because the standard atof() might be */
+/* sensitive to locale settings. */
+/* */
+/* If the calling application uses a locale with different decimal_point*/
+/* it should better also give us a locale agnostic atof() function. */
+/* */
+/* As far as I can see from Python PEP331 and GNU libc documentation */
+/* there is no standard for such a function yet. */
+/* */
+/* bernhard.reiter at intevation.de 20060924 */
+/************************************************************************/
+
+static double (* atof_function)(const char *nptr) = &atof;
+
+void SHPAPI_CALL
+ DBFSetatof_function( double (* new_atof_function)(const char *nptr))
+{
+ atof_function = new_atof_function;
+}
+
+/************************************************************************/
+/* SfRealloc() */
+/* */
+/* A realloc cover function that will access a NULL pointer as */
+/* a valid input. */
+/************************************************************************/
+
+static void * SfRealloc( void * pMem, int nNewSize )
+
+{
+ if( pMem == NULL )
+ return( (void *) malloc(nNewSize) );
+ else
+ return( (void *) realloc(pMem,nNewSize) );
+}
+
+/************************************************************************/
+/* DBFWriteHeader() */
+/* */
+/* This is called to write out the file header, and field */
+/* descriptions before writing any actual data records. This */
+/* also computes all the DBFDataSet field offset/size/decimals */
+/* and so forth values. */
+/************************************************************************/
+
+static void DBFWriteHeader(DBFHandle psDBF)
+
+{
+ unsigned char abyHeader[XBASE_FLDHDR_SZ];
+ int i;
+
+ if( !psDBF->bNoHeader )
+ return;
+
+ psDBF->bNoHeader = FALSE;
+
+/* -------------------------------------------------------------------- */
+/* Initialize the file header information. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
+ abyHeader[i] = 0;
+
+ abyHeader[0] = 0x03; /* memo field? - just copying */
+
+ /* write out a dummy date */
+ abyHeader[1] = 95; /* YY */
+ abyHeader[2] = 7; /* MM */
+ abyHeader[3] = 26; /* DD */
+
+ /* record count preset at zero */
+
+ abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
+ abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
+
+ abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
+ abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
+
+/* -------------------------------------------------------------------- */
+/* Write the initial 32 byte file header, and all the field */
+/* descriptions. */
+/* -------------------------------------------------------------------- */
+ fseek( psDBF->fp, 0, 0 );
+ fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
+ fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
+
+/* -------------------------------------------------------------------- */
+/* Write out the newline character if there is room for it. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
+ {
+ char cNewline;
+
+ cNewline = 0x0d;
+ fwrite( &cNewline, 1, 1, psDBF->fp );
+ }
+}
+
+/************************************************************************/
+/* DBFFlushRecord() */
+/* */
+/* Write out the current record if there is one. */
+/************************************************************************/
+
+static void DBFFlushRecord( DBFHandle psDBF )
+
+{
+ int nRecordOffset;
+
+ if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
+ {
+ psDBF->bCurrentRecordModified = FALSE;
+
+ nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
+ + psDBF->nHeaderLength;
+
+ fseek( psDBF->fp, nRecordOffset, 0 );
+ fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+ }
+}
+
+/************************************************************************/
+/* DBFUpdateHeader() */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFUpdateHeader( DBFHandle psDBF )
+
+{
+ unsigned char abyFileHeader[32];
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader( psDBF );
+
+ DBFFlushRecord( psDBF );
+
+ fseek( psDBF->fp, 0, 0 );
+ fread( abyFileHeader, 32, 1, psDBF->fp );
+
+ abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
+ abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
+ abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
+ abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
+
+ fseek( psDBF->fp, 0, 0 );
+ fwrite( abyFileHeader, 32, 1, psDBF->fp );
+
+ fflush( psDBF->fp );
+}
+
+/************************************************************************/
+/* DBFOpen() */
+/* */
+/* Open a .dbf file. */
+/************************************************************************/
+
+DBFHandle SHPAPI_CALL
+DBFOpen( const char * pszFilename, const char * pszAccess )
+
+{
+ DBFHandle psDBF;
+ unsigned char *pabyBuf;
+ int nFields, nHeadLen, nRecLen, iField, i;
+ char *pszBasename, *pszFullname;
+
+/* -------------------------------------------------------------------- */
+/* We only allow the access strings "rb" and "r+". */
+/* -------------------------------------------------------------------- */
+ if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
+ && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
+ && strcmp(pszAccess,"r+b") != 0 )
+ return( NULL );
+
+ if( strcmp(pszAccess,"r") == 0 )
+ pszAccess = "rb";
+
+ if( strcmp(pszAccess,"r+") == 0 )
+ pszAccess = "rb+";
+
+/* -------------------------------------------------------------------- */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
+/* -------------------------------------------------------------------- */
+ pszBasename = (char *) malloc(strlen(pszFilename)+5);
+ strcpy( pszBasename, pszFilename );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
+ i-- ) {}
+
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
+
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.dbf", pszBasename );
+
+ psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
+ psDBF->fp = fopen( pszFullname, pszAccess );
+
+ if( psDBF->fp == NULL )
+ {
+ sprintf( pszFullname, "%s.DBF", pszBasename );
+ psDBF->fp = fopen(pszFullname, pszAccess );
+ }
+
+ free( pszBasename );
+ free( pszFullname );
+
+ if( psDBF->fp == NULL )
+ {
+ free( psDBF );
+ return( NULL );
+ }
+
+ psDBF->bNoHeader = FALSE;
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+
+/* -------------------------------------------------------------------- */
+/* Read Table Header info */
+/* -------------------------------------------------------------------- */
+ pabyBuf = (unsigned char *) malloc(500);
+ if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+ {
+ fclose( psDBF->fp );
+ free( pabyBuf );
+ free( psDBF );
+ return NULL;
+ }
+
+ psDBF->nRecords =
+ pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
+
+ psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
+ psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
+
+ psDBF->nFields = nFields = (nHeadLen - 32) / 32;
+
+ psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
+
+/* -------------------------------------------------------------------- */
+/* Read in Field Definitions */
+/* -------------------------------------------------------------------- */
+
+ pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
+ psDBF->pszHeader = (char *) pabyBuf;
+
+ fseek( psDBF->fp, 32, 0 );
+ if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+ {
+ fclose( psDBF->fp );
+ free( pabyBuf );
+ free( psDBF );
+ return NULL;
+ }
+
+ psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
+ psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
+ psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
+ psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
+
+ for( iField = 0; iField < nFields; iField++ )
+ {
+ unsigned char *pabyFInfo;
+
+ pabyFInfo = pabyBuf+iField*32;
+
+ if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
+ {
+ psDBF->panFieldSize[iField] = pabyFInfo[16];
+ psDBF->panFieldDecimals[iField] = pabyFInfo[17];
+ }
+ else
+ {
+ psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
+ psDBF->panFieldDecimals[iField] = 0;
+ }
+
+ psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
+ if( iField == 0 )
+ psDBF->panFieldOffset[iField] = 1;
+ else
+ psDBF->panFieldOffset[iField] =
+ psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
+ }
+
+ return( psDBF );
+}
+
+/************************************************************************/
+/* DBFClose() */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFClose(DBFHandle psDBF)
+{
+/* -------------------------------------------------------------------- */
+/* Write out header if not already written. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->bNoHeader )
+ DBFWriteHeader( psDBF );
+
+ DBFFlushRecord( psDBF );
+
+/* -------------------------------------------------------------------- */
+/* Update last access date, and number of records if we have */
+/* write access. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->bUpdated )
+ DBFUpdateHeader( psDBF );
+
+/* -------------------------------------------------------------------- */
+/* Close, and free resources. */
+/* -------------------------------------------------------------------- */
+ fclose( psDBF->fp );
+
+ if( psDBF->panFieldOffset != NULL )
+ {
+ free( psDBF->panFieldOffset );
+ free( psDBF->panFieldSize );
+ free( psDBF->panFieldDecimals );
+ free( psDBF->pachFieldType );
+ }
+
+ free( psDBF->pszHeader );
+ free( psDBF->pszCurrentRecord );
+
+ free( psDBF );
+
+ if( pszStringField != NULL )
+ {
+ free( pszStringField );
+ pszStringField = NULL;
+ nStringFieldLen = 0;
+ }
+}
+
+/************************************************************************/
+/* DBFCreate() */
+/* */
+/* Create a new .dbf file. */
+/************************************************************************/
+
+DBFHandle SHPAPI_CALL
+DBFCreate( const char * pszFilename )
+
+{
+ DBFHandle psDBF;
+ FILE *fp;
+ char *pszFullname, *pszBasename;
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
+/* -------------------------------------------------------------------- */
+ pszBasename = (char *) malloc(strlen(pszFilename)+5);
+ strcpy( pszBasename, pszFilename );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
+ i-- ) {}
+
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
+
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.dbf", pszBasename );
+ free( pszBasename );
+
+/* -------------------------------------------------------------------- */
+/* Create the file. */
+/* -------------------------------------------------------------------- */
+ fp = fopen( pszFullname, "wb" );
+ if( fp == NULL )
+ return( NULL );
+
+ fputc( 0, fp );
+ fclose( fp );
+
+ fp = fopen( pszFullname, "rb+" );
+ if( fp == NULL )
+ return( NULL );
+
+ free( pszFullname );
+
+/* -------------------------------------------------------------------- */
+/* Create the info structure. */
+/* -------------------------------------------------------------------- */
+ psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
+
+ psDBF->fp = fp;
+ psDBF->nRecords = 0;
+ psDBF->nFields = 0;
+ psDBF->nRecordLength = 1;
+ psDBF->nHeaderLength = 33;
+
+ psDBF->panFieldOffset = NULL;
+ psDBF->panFieldSize = NULL;
+ psDBF->panFieldDecimals = NULL;
+ psDBF->pachFieldType = NULL;
+ psDBF->pszHeader = NULL;
+
+ psDBF->nCurrentRecord = -1;
+ psDBF->bCurrentRecordModified = FALSE;
+ psDBF->pszCurrentRecord = NULL;
+
+ psDBF->bNoHeader = TRUE;
+
+ return( psDBF );
+}
+
+/************************************************************************/
+/* DBFAddField() */
+/* */
+/* Add a field to a newly created .dbf file before any records */
+/* are written. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFAddField(DBFHandle psDBF, const char * pszFieldName,
+ DBFFieldType eType, int nWidth, int nDecimals )
+
+{
+ char *pszFInfo;
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* Do some checking to ensure we can add records to this file. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nRecords > 0 )
+ return( -1 );
+
+ if( !psDBF->bNoHeader )
+ return( -1 );
+
+ if( eType != FTDouble && nDecimals != 0 )
+ return( -1 );
+
+ if( nWidth < 1 )
+ return -1;
+
+/* -------------------------------------------------------------------- */
+/* SfRealloc all the arrays larger to hold the additional field */
+/* information. */
+/* -------------------------------------------------------------------- */
+ psDBF->nFields++;
+
+ psDBF->panFieldOffset = (int *)
+ SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
+
+ psDBF->panFieldSize = (int *)
+ SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
+
+ psDBF->panFieldDecimals = (int *)
+ SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
+
+ psDBF->pachFieldType = (char *)
+ SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
+
+/* -------------------------------------------------------------------- */
+/* Assign the new field information fields. */
+/* -------------------------------------------------------------------- */
+ psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
+ psDBF->nRecordLength += nWidth;
+ psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
+ psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
+
+ if( eType == FTLogical )
+ psDBF->pachFieldType[psDBF->nFields-1] = 'L';
+ else if( eType == FTString )
+ psDBF->pachFieldType[psDBF->nFields-1] = 'C';
+ else
+ psDBF->pachFieldType[psDBF->nFields-1] = 'N';
+
+/* -------------------------------------------------------------------- */
+/* Extend the required header information. */
+/* -------------------------------------------------------------------- */
+ psDBF->nHeaderLength += 32;
+ psDBF->bUpdated = FALSE;
+
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+
+ pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
+
+ for( i = 0; i < 32; i++ )
+ pszFInfo[i] = '\0';
+
+ if( (int) strlen(pszFieldName) < 10 )
+ strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
+ else
+ strncpy( pszFInfo, pszFieldName, 10);
+
+ pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
+
+ if( eType == FTString )
+ {
+ pszFInfo[16] = (unsigned char) (nWidth % 256);
+ pszFInfo[17] = (unsigned char) (nWidth / 256);
+ }
+ else
+ {
+ pszFInfo[16] = (unsigned char) nWidth;
+ pszFInfo[17] = (unsigned char) nDecimals;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Make the current record buffer appropriately larger. */
+/* -------------------------------------------------------------------- */
+ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
+ psDBF->nRecordLength);
+
+ return( psDBF->nFields-1 );
+}
+
+/************************************************************************/
+/* DBFReadAttribute() */
+/* */
+/* Read one of the attribute fields of a record. */
+/************************************************************************/
+
+static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
+ char chReqType )
+
+{
+ int nRecordOffset;
+ unsigned char *pabyRec;
+ void *pReturnField = NULL;
+
+ static double dDoubleField;
+
+/* -------------------------------------------------------------------- */
+/* Verify selection. */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity >= psDBF->nRecords )
+ return( NULL );
+
+ if( iField < 0 || iField >= psDBF->nFields )
+ return( NULL );
+
+/* -------------------------------------------------------------------- */
+/* Have we read the record? */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+ if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
+ {
+ fprintf( stderr, "fseek(%d) failed on DBF file.\n",
+ nRecordOffset );
+ return NULL;
+ }
+
+ if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
+ 1, psDBF->fp ) != 1 )
+ {
+ fprintf( stderr, "fread(%d) failed on DBF file.\n",
+ psDBF->nRecordLength );
+ return NULL;
+ }
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
+
+/* -------------------------------------------------------------------- */
+/* Ensure our field buffer is large enough to hold this buffer. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
+ {
+ nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
+ pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
+ }
+
+/* -------------------------------------------------------------------- */
+/* Extract the requested field. */
+/* -------------------------------------------------------------------- */
+ strncpy( pszStringField,
+ ((const char *) pabyRec) + psDBF->panFieldOffset[iField],
+ psDBF->panFieldSize[iField] );
+ pszStringField[psDBF->panFieldSize[iField]] = '\0';
+
+ pReturnField = pszStringField;
+
+/* -------------------------------------------------------------------- */
+/* Decode the field. */
+/* -------------------------------------------------------------------- */
+ if( chReqType == 'N' )
+ {
+ dDoubleField = (*atof_function)(pszStringField);
+
+ pReturnField = &dDoubleField;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Should we trim white space off the string attribute value? */
+/* -------------------------------------------------------------------- */
+#ifdef TRIM_DBF_WHITESPACE
+ else
+ {
+ char *pchSrc, *pchDst;
+
+ pchDst = pchSrc = pszStringField;
+ while( *pchSrc == ' ' )
+ pchSrc++;
+
+ while( *pchSrc != '\0' )
+ *(pchDst++) = *(pchSrc++);
+ *pchDst = '\0';
+
+ while( pchDst != pszStringField && *(--pchDst) == ' ' )
+ *pchDst = '\0';
+ }
+#endif
+
+ return( pReturnField );
+}
+
+/************************************************************************/
+/* DBFReadIntAttribute() */
+/* */
+/* Read an integer attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ double *pdValue;
+
+ pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
+
+ if( pdValue == NULL )
+ return 0;
+ else
+ return( (int) *pdValue );
+}
+
+/************************************************************************/
+/* DBFReadDoubleAttribute() */
+/* */
+/* Read a double attribute. */
+/************************************************************************/
+
+double SHPAPI_CALL
+DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ double *pdValue;
+
+ pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
+
+ if( pdValue == NULL )
+ return 0.0;
+ else
+ return( *pdValue );
+}
+
+/************************************************************************/
+/* DBFReadStringAttribute() */
+/* */
+/* Read a string attribute. */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
+}
+
+/************************************************************************/
+/* DBFReadLogicalAttribute() */
+/* */
+/* Read a logical attribute. */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
+}
+
+/************************************************************************/
+/* DBFIsAttributeNULL() */
+/* */
+/* Return TRUE if value for field is NULL. */
+/* */
+/* Contributed by Jim Matthews. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ const char *pszValue;
+
+ pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
+
+ if( pszValue == NULL )
+ return TRUE;
+
+ switch(psDBF->pachFieldType[iField])
+ {
+ case 'N':
+ case 'F':
+ /* NULL numeric fields have value "****************" */
+ return pszValue[0] == '*';
+
+ case 'D':
+ /* NULL date fields have value "00000000" */
+ return strncmp(pszValue,"00000000",8) == 0;
+
+ case 'L':
+ /* NULL boolean fields have value "?" */
+ return pszValue[0] == '?';
+
+ default:
+ /* empty string fields are considered NULL */
+ return strlen(pszValue) == 0;
+ }
+}
+
+/************************************************************************/
+/* DBFGetFieldCount() */
+/* */
+/* Return the number of fields in this table. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFGetFieldCount( DBFHandle psDBF )
+
+{
+ return( psDBF->nFields );
+}
+
+/************************************************************************/
+/* DBFGetRecordCount() */
+/* */
+/* Return the number of records in this table. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFGetRecordCount( DBFHandle psDBF )
+
+{
+ return( psDBF->nRecords );
+}
+
+/************************************************************************/
+/* DBFGetFieldInfo() */
+/* */
+/* Return any requested information about the field. */
+/************************************************************************/
+
+DBFFieldType SHPAPI_CALL
+DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
+ int * pnWidth, int * pnDecimals )
+
+{
+ if( iField < 0 || iField >= psDBF->nFields )
+ return( FTInvalid );
+
+ if( pnWidth != NULL )
+ *pnWidth = psDBF->panFieldSize[iField];
+
+ if( pnDecimals != NULL )
+ *pnDecimals = psDBF->panFieldDecimals[iField];
+
+ if( pszFieldName != NULL )
+ {
+ int i;
+
+ strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
+ pszFieldName[11] = '\0';
+ for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
+ pszFieldName[i] = '\0';
+ }
+
+ if ( psDBF->pachFieldType[iField] == 'L' )
+ return( FTLogical);
+
+ else if( psDBF->pachFieldType[iField] == 'N'
+ || psDBF->pachFieldType[iField] == 'F'
+ || psDBF->pachFieldType[iField] == 'D' )
+ {
+ if( psDBF->panFieldDecimals[iField] > 0 )
+ return( FTDouble );
+ else
+ return( FTInteger );
+ }
+ else
+ {
+ return( FTString );
+ }
+}
+
+/************************************************************************/
+/* DBFWriteAttribute() */
+/* */
+/* Write an attribute record to the file. */
+/************************************************************************/
+
+static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
+ void * pValue )
+
+{
+ int nRecordOffset, i, j, nRetResult = TRUE;
+ unsigned char *pabyRec;
+ char szSField[400], szFormat[20];
+
+/* -------------------------------------------------------------------- */
+/* Is this a valid record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
+ return( FALSE );
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader(psDBF);
+
+/* -------------------------------------------------------------------- */
+/* Is this a brand new record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity == psDBF->nRecords )
+ {
+ DBFFlushRecord( psDBF );
+
+ psDBF->nRecords++;
+ for( i = 0; i < psDBF->nRecordLength; i++ )
+ psDBF->pszCurrentRecord[i] = ' ';
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Is this an existing record, but different than the last one */
+/* we accessed? */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+ fseek( psDBF->fp, nRecordOffset, 0 );
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
+
+ psDBF->bCurrentRecordModified = TRUE;
+ psDBF->bUpdated = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Translate NULL value to valid DBF file representation. */
+/* */
+/* Contributed by Jim Matthews. */
+/* -------------------------------------------------------------------- */
+ if( pValue == NULL )
+ {
+ switch(psDBF->pachFieldType[iField])
+ {
+ case 'N':
+ case 'F':
+ /* NULL numeric fields have value "****************" */
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
+ psDBF->panFieldSize[iField] );
+ break;
+
+ case 'D':
+ /* NULL date fields have value "00000000" */
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
+ psDBF->panFieldSize[iField] );
+ break;
+
+ case 'L':
+ /* NULL boolean fields have value "?" */
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
+ psDBF->panFieldSize[iField] );
+ break;
+
+ default:
+ /* empty string fields are considered NULL */
+ memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
+ psDBF->panFieldSize[iField] );
+ break;
+ }
+ return TRUE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Assign all the record fields. */
+/* -------------------------------------------------------------------- */
+ switch( psDBF->pachFieldType[iField] )
+ {
+ case 'D':
+ case 'N':
+ case 'F':
+ if( psDBF->panFieldDecimals[iField] == 0 )
+ {
+ int nWidth = psDBF->panFieldSize[iField];
+
+ if( sizeof(szSField)-2 < nWidth )
+ nWidth = sizeof(szSField)-2;
+
+ sprintf( szFormat, "%%%dd", nWidth );
+ sprintf(szSField, szFormat, (int) *((double *) pValue) );
+ if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
+ {
+ szSField[psDBF->panFieldSize[iField]] = '\0';
+ nRetResult = FALSE;
+ }
+
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ szSField, strlen(szSField) );
+ }
+ else
+ {
+ int nWidth = psDBF->panFieldSize[iField];
+
+ if( sizeof(szSField)-2 < nWidth )
+ nWidth = sizeof(szSField)-2;
+
+ sprintf( szFormat, "%%%d.%df",
+ nWidth, psDBF->panFieldDecimals[iField] );
+ sprintf(szSField, szFormat, *((double *) pValue) );
+ if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
+ {
+ szSField[psDBF->panFieldSize[iField]] = '\0';
+ nRetResult = FALSE;
+ }
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ szSField, strlen(szSField) );
+ }
+ break;
+
+ case 'L':
+ if (psDBF->panFieldSize[iField] >= 1 &&
+ (*(char*)pValue == 'F' || *(char*)pValue == 'T'))
+ *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
+ break;
+
+ default:
+ if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
+ {
+ j = psDBF->panFieldSize[iField];
+ nRetResult = FALSE;
+ }
+ else
+ {
+ memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
+ psDBF->panFieldSize[iField] );
+ j = strlen((char *) pValue);
+ }
+
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ (char *) pValue, j );
+ break;
+ }
+
+ return( nRetResult );
+}
+
+/************************************************************************/
+/* DBFWriteAttributeDirectly() */
+/* */
+/* Write an attribute record to the file, but without any */
+/* reformatting based on type. The provided buffer is written */
+/* as is to the field position in the record. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
+ void * pValue )
+
+{
+ int nRecordOffset, i, j;
+ unsigned char *pabyRec;
+
+/* -------------------------------------------------------------------- */
+/* Is this a valid record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
+ return( FALSE );
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader(psDBF);
+
+/* -------------------------------------------------------------------- */
+/* Is this a brand new record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity == psDBF->nRecords )
+ {
+ DBFFlushRecord( psDBF );
+
+ psDBF->nRecords++;
+ for( i = 0; i < psDBF->nRecordLength; i++ )
+ psDBF->pszCurrentRecord[i] = ' ';
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Is this an existing record, but different than the last one */
+/* we accessed? */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+ fseek( psDBF->fp, nRecordOffset, 0 );
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
+
+/* -------------------------------------------------------------------- */
+/* Assign all the record fields. */
+/* -------------------------------------------------------------------- */
+ if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
+ j = psDBF->panFieldSize[iField];
+ else
+ {
+ memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
+ psDBF->panFieldSize[iField] );
+ j = strlen((char *) pValue);
+ }
+
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ (char *) pValue, j );
+
+ psDBF->bCurrentRecordModified = TRUE;
+ psDBF->bUpdated = TRUE;
+
+ return( TRUE );
+}
+
+/************************************************************************/
+/* DBFWriteDoubleAttribute() */
+/* */
+/* Write a double attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
+ double dValue )
+
+{
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
+}
+
+/************************************************************************/
+/* DBFWriteIntegerAttribute() */
+/* */
+/* Write a integer attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
+ int nValue )
+
+{
+ double dValue = nValue;
+
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
+}
+
+/************************************************************************/
+/* DBFWriteStringAttribute() */
+/* */
+/* Write a string attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
+ const char * pszValue )
+
+{
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
+}
+
+/************************************************************************/
+/* DBFWriteNULLAttribute() */
+/* */
+/* Write a string attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
+
+{
+ return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
+}
+
+/************************************************************************/
+/* DBFWriteLogicalAttribute() */
+/* */
+/* Write a logical attribute. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
+ const char lValue)
+
+{
+ return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
+}
+
+/************************************************************************/
+/* DBFWriteTuple() */
+/* */
+/* Write an attribute record to the file. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
+
+{
+ int nRecordOffset, i;
+ unsigned char *pabyRec;
+
+/* -------------------------------------------------------------------- */
+/* Is this a valid record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity > psDBF->nRecords )
+ return( FALSE );
+
+ if( psDBF->bNoHeader )
+ DBFWriteHeader(psDBF);
+
+/* -------------------------------------------------------------------- */
+/* Is this a brand new record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity == psDBF->nRecords )
+ {
+ DBFFlushRecord( psDBF );
+
+ psDBF->nRecords++;
+ for( i = 0; i < psDBF->nRecordLength; i++ )
+ psDBF->pszCurrentRecord[i] = ' ';
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Is this an existing record, but different than the last one */
+/* we accessed? */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+ fseek( psDBF->fp, nRecordOffset, 0 );
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
+
+ memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
+
+ psDBF->bCurrentRecordModified = TRUE;
+ psDBF->bUpdated = TRUE;
+
+ return( TRUE );
+}
+
+/************************************************************************/
+/* DBFReadTuple() */
+/* */
+/* Read one of the attribute fields of a record. */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+DBFReadTuple(DBFHandle psDBF, int hEntity )
+
+{
+ int nRecordOffset;
+ unsigned char *pabyRec;
+ static char *pReturnTuple = NULL;
+
+ static int nTupleLen = 0;
+
+/* -------------------------------------------------------------------- */
+/* Have we read the record? */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity >= psDBF->nRecords )
+ return( NULL );
+
+ if( psDBF->nCurrentRecord != hEntity )
+ {
+ DBFFlushRecord( psDBF );
+
+ nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
+
+ fseek( psDBF->fp, nRecordOffset, 0 );
+ fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
+
+ psDBF->nCurrentRecord = hEntity;
+ }
+
+ pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
+
+ if ( nTupleLen < psDBF->nRecordLength) {
+ nTupleLen = psDBF->nRecordLength;
+ pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
+ }
+
+ memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
+
+ return( pReturnTuple );
+}
+
+/************************************************************************/
+/* DBFCloneEmpty() */
+/* */
+/* Read one of the attribute fields of a record. */
+/************************************************************************/
+
+DBFHandle SHPAPI_CALL
+DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
+{
+ DBFHandle newDBF;
+
+ newDBF = DBFCreate ( pszFilename );
+ if ( newDBF == NULL ) return ( NULL );
+
+ newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
+ memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
+
+ newDBF->nFields = psDBF->nFields;
+ newDBF->nRecordLength = psDBF->nRecordLength;
+ newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
+
+ newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
+ memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
+ newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
+ memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
+ newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
+ memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
+ newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
+ memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
+
+ newDBF->bNoHeader = TRUE;
+ newDBF->bUpdated = TRUE;
+
+ DBFWriteHeader ( newDBF );
+ DBFClose ( newDBF );
+
+ newDBF = DBFOpen ( pszFilename, "rb+" );
+
+ return ( newDBF );
+}
+
+/************************************************************************/
+/* DBFGetNativeFieldType() */
+/* */
+/* Return the DBase field type for the specified field. */
+/* */
+/* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
+/* 'N' (Numeric, with or without decimal), */
+/* 'L' (Logical), */
+/* 'M' (Memo: 10 digits .DBT block ptr) */
+/************************************************************************/
+
+char SHPAPI_CALL
+DBFGetNativeFieldType( DBFHandle psDBF, int iField )
+
+{
+ if( iField >=0 && iField < psDBF->nFields )
+ return psDBF->pachFieldType[iField];
+
+ return ' ';
+}
+
+/************************************************************************/
+/* str_to_upper() */
+/************************************************************************/
+
+static void str_to_upper (char *string)
+{
+ int len;
+ short i = -1;
+
+ len = strlen (string);
+
+ while (++i < len)
+ if (isalpha(string[i]) && islower(string[i]))
+ string[i] = (char) toupper ((int)string[i]);
+}
+
+/************************************************************************/
+/* DBFGetFieldIndex() */
+/* */
+/* Get the index number for a field in a .dbf file. */
+/* */
+/* Contributed by Jim Matthews. */
+/************************************************************************/
+
+int SHPAPI_CALL
+DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
+
+{
+ char name[12], name1[12], name2[12];
+ int i;
+
+ strncpy(name1, pszFieldName,11);
+ name1[11] = '\0';
+ str_to_upper(name1);
+
+ for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
+ {
+ DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
+ strncpy(name2,name,11);
+ str_to_upper(name2);
+
+ if(!strncmp(name1,name2,10))
+ return(i);
+ }
+ return(-1);
+}
Added: packages/thuban/branches/upstream/current/libraries/shapelib/shapefil.h
===================================================================
--- packages/thuban/branches/upstream/current/libraries/shapelib/shapefil.h 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/shapelib/shapefil.h 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,539 @@
+#ifndef _SHAPEFILE_H_INCLUDED
+#define _SHAPEFILE_H_INCLUDED
+
+/******************************************************************************
+ * $Id: shapefil.h 2703 2006-09-24 18:51:39Z bernhard $
+ *
+ * Project: Shapelib
+ * Purpose: Primary include file for Shapelib.
+ * Author: Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * This software is available under the following "MIT Style" license,
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * option is discussed in more detail in shapelib.html.
+ *
+ * --
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log$
+ * Revision 1.3 2004/05/17 15:47:57 bh
+ * Update to newest shapelib and get rid of Thuban specific extensions,
+ * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ *
+ * * libraries/shapelib/shpopen.c: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/shapefil.h: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/dbfopen.c: Update to version from current
+ * shapelib CVS.
+ * (DBFCommit): Effectively removed since shapelib itself has
+ * DBFUpdateHeader now which is better for what DBFCommit wanted to
+ * achieve.
+ * We're now using an unmodified version of dbfopen.
+ *
+ * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
+ * Update from dbflib.i
+ *
+ * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
+ * the commit method. This new indirection is necessary because we use the
+ * DBFUpdateHeader function now which is not available in shapelib <=
+ * 1.2.10
+ * (DBFFile::commit): Use DBFInfo_commit as implementation
+ * (pragma __class__): New. Kludge to remove the commit method when
+ * the DBFUpdateHeader function isn't available
+ * (_have_commit): New. Helper for the pragma kludge.
+ *
+ * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
+ * preprocessor macros needed to compile the dbflib wrapper. Determine
+ * whether DBFUpdateHeader is available and define the right value of
+ * HAVE_UPDATE_HEADER
+ * (extensions): Use dbf_macros for the dbflibc extension
+ *
+ * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
+ * value '1' to the Lib.dbflibc extension. This simply reflects the
+ * shapelib and pyshapelib updates
+ *
+ * Revision 1.28 2003/12/29 06:02:18 fwarmerdam
+ * added cpl_error.h option
+ *
+ * Revision 1.27 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.26 2002/09/29 00:00:08 warmerda
+ * added FTLogical and logical attribute read/write calls
+ *
+ * Revision 1.25 2002/05/07 13:46:30 warmerda
+ * added DBFWriteAttributeDirectly().
+ *
+ * Revision 1.24 2002/04/10 16:59:54 warmerda
+ * added SHPRewindObject
+ *
+ * Revision 1.23 2002/01/15 14:36:07 warmerda
+ * updated email address
+ *
+ * Revision 1.22 2002/01/15 14:32:00 warmerda
+ * try to improve SHPAPI_CALL docs
+ *
+ * Revision 1.21 2001/11/01 16:29:55 warmerda
+ * move pabyRec into SHPInfo for thread safety
+ *
+ * Revision 1.20 2001/07/20 13:06:02 warmerda
+ * fixed SHPAPI attribute for SHPTreeFindLikelyShapes
+ *
+ * Revision 1.19 2001/05/31 19:20:13 warmerda
+ * added DBFGetFieldIndex()
+ *
+ * Revision 1.18 2001/05/31 18:15:40 warmerda
+ * Added support for NULL fields in DBF files
+ *
+ * Revision 1.17 2001/05/23 13:36:52 warmerda
+ * added use of SHPAPI_CALL
+ *
+ * Revision 1.16 2000/09/25 14:15:59 warmerda
+ * added DBFGetNativeFieldType()
+ *
+ * Revision 1.15 2000/02/16 16:03:51 warmerda
+ * added null shape support
+ *
+ * Revision 1.14 1999/11/05 14:12:05 warmerda
+ * updated license terms
+ *
+ * Revision 1.13 1999/06/02 18:24:21 warmerda
+ * added trimming code
+ *
+ * Revision 1.12 1999/06/02 17:56:12 warmerda
+ * added quad'' subnode support for trees
+ *
+ * Revision 1.11 1999/05/18 19:11:11 warmerda
+ * Added example searching capability
+ *
+ * Revision 1.10 1999/05/18 17:49:38 warmerda
+ * added initial quadtree support
+ *
+ * Revision 1.9 1999/05/11 03:19:28 warmerda
+ * added new Tuple api, and improved extension handling - add from candrsn
+ *
+ * Revision 1.8 1999/03/23 17:22:27 warmerda
+ * Added extern "C" protection for C++ users of shapefil.h.
+ *
+ * Revision 1.7 1998/12/31 15:31:07 warmerda
+ * Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options.
+ *
+ * Revision 1.6 1998/12/03 15:48:15 warmerda
+ * Added SHPCalculateExtents().
+ *
+ * Revision 1.5 1998/11/09 20:57:16 warmerda
+ * Altered SHPGetInfo() call.
+ *
+ * Revision 1.4 1998/11/09 20:19:33 warmerda
+ * Added 3D support, and use of SHPObject.
+ *
+ * Revision 1.3 1995/08/23 02:24:05 warmerda
+ * Added support for reading bounds.
+ *
+ * Revision 1.2 1995/08/04 03:17:39 warmerda
+ * Added header.
+ *
+ */
+
+#include <stdio.h>
+
+#ifdef USE_DBMALLOC
+#include <dbmalloc.h>
+#endif
+
+#ifdef USE_CPL
+#include "cpl_error.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************************************************************/
+/* Configuration options. */
+/************************************************************************/
+
+/* -------------------------------------------------------------------- */
+/* Should the DBFReadStringAttribute() strip leading and */
+/* trailing white space? */
+/* -------------------------------------------------------------------- */
+#define TRIM_DBF_WHITESPACE
+
+/* -------------------------------------------------------------------- */
+/* Should we write measure values to the Multipatch object? */
+/* Reportedly ArcView crashes if we do write it, so for now it */
+/* is disabled. */
+/* -------------------------------------------------------------------- */
+#define DISABLE_MULTIPATCH_MEASURE
+
+/* -------------------------------------------------------------------- */
+/* SHPAPI_CALL */
+/* */
+/* The following two macros are present to allow forcing */
+/* various calling conventions on the Shapelib API. */
+/* */
+/* To force __stdcall conventions (needed to call Shapelib */
+/* from Visual Basic and/or Dephi I believe) the makefile could */
+/* be modified to define: */
+/* */
+/* /DSHPAPI_CALL=__stdcall */
+/* */
+/* If it is desired to force export of the Shapelib API without */
+/* using the shapelib.def file, use the following definition. */
+/* */
+/* /DSHAPELIB_DLLEXPORT */
+/* */
+/* To get both at once it will be necessary to hack this */
+/* include file to define: */
+/* */
+/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */
+/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */
+/* */
+/* The complexity of the situtation is partly caused by the */
+/* peculiar requirement of Visual C++ that __stdcall appear */
+/* after any "*"'s in the return value of a function while the */
+/* __declspec(dllexport) must appear before them. */
+/* -------------------------------------------------------------------- */
+
+#ifdef SHAPELIB_DLLEXPORT
+# define SHPAPI_CALL __declspec(dllexport)
+# define SHPAPI_CALL1(x) __declspec(dllexport) x
+#endif
+
+#ifndef SHPAPI_CALL
+# define SHPAPI_CALL
+#endif
+
+#ifndef SHPAPI_CALL1
+# define SHPAPI_CALL1(x) x SHPAPI_CALL
+#endif
+
+/************************************************************************/
+/* SHP Support. */
+/************************************************************************/
+typedef struct
+{
+ FILE *fpSHP;
+ FILE *fpSHX;
+
+ int nShapeType; /* SHPT_* */
+
+ int nFileSize; /* SHP file */
+
+ int nRecords;
+ int nMaxRecords;
+ int *panRecOffset;
+ int *panRecSize;
+
+ double adBoundsMin[4];
+ double adBoundsMax[4];
+
+ int bUpdated;
+
+ unsigned char *pabyRec;
+ int nBufSize;
+} SHPInfo;
+
+typedef SHPInfo * SHPHandle;
+
+/* -------------------------------------------------------------------- */
+/* Shape types (nSHPType) */
+/* -------------------------------------------------------------------- */
+#define SHPT_NULL 0
+#define SHPT_POINT 1
+#define SHPT_ARC 3
+#define SHPT_POLYGON 5
+#define SHPT_MULTIPOINT 8
+#define SHPT_POINTZ 11
+#define SHPT_ARCZ 13
+#define SHPT_POLYGONZ 15
+#define SHPT_MULTIPOINTZ 18
+#define SHPT_POINTM 21
+#define SHPT_ARCM 23
+#define SHPT_POLYGONM 25
+#define SHPT_MULTIPOINTM 28
+#define SHPT_MULTIPATCH 31
+
+
+/* -------------------------------------------------------------------- */
+/* Part types - everything but SHPT_MULTIPATCH just uses */
+/* SHPP_RING. */
+/* -------------------------------------------------------------------- */
+
+#define SHPP_TRISTRIP 0
+#define SHPP_TRIFAN 1
+#define SHPP_OUTERRING 2
+#define SHPP_INNERRING 3
+#define SHPP_FIRSTRING 4
+#define SHPP_RING 5
+
+/* -------------------------------------------------------------------- */
+/* SHPObject - represents on shape (without attributes) read */
+/* from the .shp file. */
+/* -------------------------------------------------------------------- */
+typedef struct
+{
+ int nSHPType;
+
+ int nShapeId; /* -1 is unknown/unassigned */
+
+ int nParts;
+ int *panPartStart;
+ int *panPartType;
+
+ int nVertices;
+ double *padfX;
+ double *padfY;
+ double *padfZ;
+ double *padfM;
+
+ double dfXMin;
+ double dfYMin;
+ double dfZMin;
+ double dfMMin;
+
+ double dfXMax;
+ double dfYMax;
+ double dfZMax;
+ double dfMMax;
+} SHPObject;
+
+/* -------------------------------------------------------------------- */
+/* SHP API Prototypes */
+/* -------------------------------------------------------------------- */
+SHPHandle SHPAPI_CALL
+ SHPOpen( const char * pszShapeFile, const char * pszAccess );
+SHPHandle SHPAPI_CALL
+ SHPCreate( const char * pszShapeFile, int nShapeType );
+void SHPAPI_CALL
+ SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
+ double * padfMinBound, double * padfMaxBound );
+
+SHPObject SHPAPI_CALL1(*)
+ SHPReadObject( SHPHandle hSHP, int iShape );
+int SHPAPI_CALL
+ SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject );
+
+void SHPAPI_CALL
+ SHPDestroyObject( SHPObject * psObject );
+void SHPAPI_CALL
+ SHPComputeExtents( SHPObject * psObject );
+SHPObject SHPAPI_CALL1(*)
+ SHPCreateObject( int nSHPType, int nShapeId,
+ int nParts, int * panPartStart, int * panPartType,
+ int nVertices, double * padfX, double * padfY,
+ double * padfZ, double * padfM );
+SHPObject SHPAPI_CALL1(*)
+ SHPCreateSimpleObject( int nSHPType, int nVertices,
+ double * padfX, double * padfY, double * padfZ );
+
+int SHPAPI_CALL
+ SHPRewindObject( SHPHandle hSHP, SHPObject * psObject );
+
+void SHPAPI_CALL SHPClose( SHPHandle hSHP );
+void SHPAPI_CALL SHPWriteHeader( SHPHandle hSHP );
+
+const char SHPAPI_CALL1(*)
+ SHPTypeName( int nSHPType );
+const char SHPAPI_CALL1(*)
+ SHPPartTypeName( int nPartType );
+
+/* -------------------------------------------------------------------- */
+/* Shape quadtree indexing API. */
+/* -------------------------------------------------------------------- */
+
+/* this can be two or four for binary or quad tree */
+#define MAX_SUBNODE 4
+
+typedef struct shape_tree_node
+{
+ /* region covered by this node */
+ double adfBoundsMin[4];
+ double adfBoundsMax[4];
+
+ /* list of shapes stored at this node. The papsShapeObj pointers
+ or the whole list can be NULL */
+ int nShapeCount;
+ int *panShapeIds;
+ SHPObject **papsShapeObj;
+
+ int nSubNodes;
+ struct shape_tree_node *apsSubNode[MAX_SUBNODE];
+
+} SHPTreeNode;
+
+typedef struct
+{
+ SHPHandle hSHP;
+
+ int nMaxDepth;
+ int nDimension;
+
+ SHPTreeNode *psRoot;
+} SHPTree;
+
+SHPTree SHPAPI_CALL1(*)
+ SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
+ double *padfBoundsMin, double *padfBoundsMax );
+void SHPAPI_CALL
+ SHPDestroyTree( SHPTree * hTree );
+
+int SHPAPI_CALL
+ SHPWriteTree( SHPTree *hTree, const char * pszFilename );
+SHPTree SHPAPI_CALL
+ SHPReadTree( const char * pszFilename );
+
+int SHPAPI_CALL
+ SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject );
+int SHPAPI_CALL
+ SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
+int SHPAPI_CALL
+ SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
+
+void SHPAPI_CALL
+ SHPTreeTrimExtraNodes( SHPTree * hTree );
+
+int SHPAPI_CALL1(*)
+ SHPTreeFindLikelyShapes( SHPTree * hTree,
+ double * padfBoundsMin,
+ double * padfBoundsMax,
+ int * );
+int SHPAPI_CALL
+ SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
+
+/************************************************************************/
+/* DBF Support. */
+/************************************************************************/
+typedef struct
+{
+ FILE *fp;
+
+ int nRecords;
+
+ int nRecordLength;
+ int nHeaderLength;
+ int nFields;
+ int *panFieldOffset;
+ int *panFieldSize;
+ int *panFieldDecimals;
+ char *pachFieldType;
+
+ char *pszHeader;
+
+ int nCurrentRecord;
+ int bCurrentRecordModified;
+ char *pszCurrentRecord;
+
+ int bNoHeader;
+ int bUpdated;
+} DBFInfo;
+
+typedef DBFInfo * DBFHandle;
+
+typedef enum {
+ FTString,
+ FTInteger,
+ FTDouble,
+ FTLogical,
+ FTInvalid
+} DBFFieldType;
+
+#define XBASE_FLDHDR_SZ 32
+
+/* to hand over a locale agnostic atof function, if decimal_point != ".\0" */
+void SHPAPI_CALL
+ DBFSetatof_function( double (* new_atof_function)(const char *nptr));
+
+DBFHandle SHPAPI_CALL
+ DBFOpen( const char * pszDBFFile, const char * pszAccess );
+DBFHandle SHPAPI_CALL
+ DBFCreate( const char * pszDBFFile );
+
+int SHPAPI_CALL
+ DBFGetFieldCount( DBFHandle psDBF );
+int SHPAPI_CALL
+ DBFGetRecordCount( DBFHandle psDBF );
+int SHPAPI_CALL
+ DBFAddField( DBFHandle hDBF, const char * pszFieldName,
+ DBFFieldType eType, int nWidth, int nDecimals );
+
+DBFFieldType SHPAPI_CALL
+ DBFGetFieldInfo( DBFHandle psDBF, int iField,
+ char * pszFieldName, int * pnWidth, int * pnDecimals );
+
+int SHPAPI_CALL
+ DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);
+
+int SHPAPI_CALL
+ DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
+double SHPAPI_CALL
+ DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
+const char SHPAPI_CALL1(*)
+ DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
+const char SHPAPI_CALL1(*)
+ DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
+int SHPAPI_CALL
+ DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
+
+int SHPAPI_CALL
+ DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
+ int nFieldValue );
+int SHPAPI_CALL
+ DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
+ double dFieldValue );
+int SHPAPI_CALL
+ DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
+ const char * pszFieldValue );
+int SHPAPI_CALL
+ DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );
+
+int SHPAPI_CALL
+ DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
+ const char lFieldValue);
+int SHPAPI_CALL
+ DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
+ void * pValue );
+const char SHPAPI_CALL1(*)
+ DBFReadTuple(DBFHandle psDBF, int hEntity );
+int SHPAPI_CALL
+ DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );
+
+DBFHandle SHPAPI_CALL
+ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
+
+void SHPAPI_CALL
+ DBFClose( DBFHandle hDBF );
+void SHPAPI_CALL
+ DBFUpdateHeader( DBFHandle hDBF );
+char SHPAPI_CALL
+ DBFGetNativeFieldType( DBFHandle hDBF, int iField );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ndef _SHAPEFILE_H_INCLUDED */
Added: packages/thuban/branches/upstream/current/libraries/shapelib/shpopen.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/shapelib/shpopen.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/shapelib/shpopen.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,2035 @@
+/******************************************************************************
+ * $Id: shpopen.c 2212 2004-05-17 15:47:57Z bh $
+ *
+ * Project: Shapelib
+ * Purpose: Implementation of core Shapefile read/write functions.
+ * Author: Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, 2001, Frank Warmerdam
+ *
+ * This software is available under the following "MIT Style" license,
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * option is discussed in more detail in shapelib.html.
+ *
+ * --
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log$
+ * Revision 1.3 2004/05/17 15:47:57 bh
+ * Update to newest shapelib and get rid of Thuban specific extensions,
+ * i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge
+ *
+ * * libraries/shapelib/shpopen.c: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/shapefil.h: Update to version from current
+ * shapelib CVS.
+ *
+ * * libraries/shapelib/dbfopen.c: Update to version from current
+ * shapelib CVS.
+ * (DBFCommit): Effectively removed since shapelib itself has
+ * DBFUpdateHeader now which is better for what DBFCommit wanted to
+ * achieve.
+ * We're now using an unmodified version of dbfopen.
+ *
+ * * libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
+ * Update from dbflib.i
+ *
+ * * libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
+ * the commit method. This new indirection is necessary because we use the
+ * DBFUpdateHeader function now which is not available in shapelib <=
+ * 1.2.10
+ * (DBFFile::commit): Use DBFInfo_commit as implementation
+ * (pragma __class__): New. Kludge to remove the commit method when
+ * the DBFUpdateHeader function isn't available
+ * (_have_commit): New. Helper for the pragma kludge.
+ *
+ * * libraries/pyshapelib/setup.py (dbf_macros): New. Return the
+ * preprocessor macros needed to compile the dbflib wrapper. Determine
+ * whether DBFUpdateHeader is available and define the right value of
+ * HAVE_UPDATE_HEADER
+ * (extensions): Use dbf_macros for the dbflibc extension
+ *
+ * * setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
+ * value '1' to the Lib.dbflibc extension. This simply reflects the
+ * shapelib and pyshapelib updates
+ *
+ * Revision 1.44 2003/12/29 00:18:39 fwarmerdam
+ * added error checking for failed IO and optional CPL error reporting
+ *
+ * Revision 1.43 2003/12/01 16:20:08 warmerda
+ * be careful of zero vertex shapes
+ *
+ * Revision 1.42 2003/12/01 14:58:27 warmerda
+ * added degenerate object check in SHPRewindObject()
+ *
+ * Revision 1.41 2003/07/08 15:22:43 warmerda
+ * avoid warning
+ *
+ * Revision 1.40 2003/04/21 18:30:37 warmerda
+ * added header write/update public methods
+ *
+ * Revision 1.39 2002/08/26 06:46:56 warmerda
+ * avoid c++ comments
+ *
+ * Revision 1.38 2002/05/07 16:43:39 warmerda
+ * Removed debugging printf.
+ *
+ * Revision 1.37 2002/04/10 17:35:22 warmerda
+ * fixed bug in ring reversal code
+ *
+ * Revision 1.36 2002/04/10 16:59:54 warmerda
+ * added SHPRewindObject
+ *
+ * Revision 1.35 2001/12/07 15:10:44 warmerda
+ * fix if .shx fails to open
+ *
+ * Revision 1.34 2001/11/01 16:29:55 warmerda
+ * move pabyRec into SHPInfo for thread safety
+ *
+ * Revision 1.33 2001/07/03 12:18:15 warmerda
+ * Improved cleanup if SHX not found, provied by Riccardo Cohen.
+ *
+ * Revision 1.32 2001/06/22 01:58:07 warmerda
+ * be more careful about establishing initial bounds in face of NULL shapes
+ *
+ * Revision 1.31 2001/05/31 19:35:29 warmerda
+ * added support for writing null shapes
+ *
+ * Revision 1.30 2001/05/28 12:46:29 warmerda
+ * Add some checking on reasonableness of record count when opening.
+ *
+ * Revision 1.29 2001/05/23 13:36:52 warmerda
+ * added use of SHPAPI_CALL
+ *
+ * Revision 1.28 2001/02/06 22:25:06 warmerda
+ * fixed memory leaks when SHPOpen() fails
+ *
+ * Revision 1.27 2000/07/18 15:21:33 warmerda
+ * added better enforcement of -1 for append in SHPWriteObject
+ *
+ * Revision 1.26 2000/02/16 16:03:51 warmerda
+ * added null shape support
+ *
+ * Revision 1.25 1999/12/15 13:47:07 warmerda
+ * Fixed record size settings in .shp file (was 4 words too long)
+ * Added stdlib.h.
+ *
+ * Revision 1.24 1999/11/05 14:12:04 warmerda
+ * updated license terms
+ *
+ * Revision 1.23 1999/07/27 00:53:46 warmerda
+ * added support for rewriting shapes
+ *
+ * Revision 1.22 1999/06/11 19:19:11 warmerda
+ * Cleanup pabyRec static buffer on SHPClose().
+ *
+ * Revision 1.21 1999/06/02 14:57:56 kshih
+ * Remove unused variables
+ *
+ * Revision 1.20 1999/04/19 21:04:17 warmerda
+ * Fixed syntax error.
+ *
+ * Revision 1.19 1999/04/19 21:01:57 warmerda
+ * Force access string to binary in SHPOpen().
+ *
+ * Revision 1.18 1999/04/01 18:48:07 warmerda
+ * Try upper case extensions if lower case doesn't work.
+ *
+ * Revision 1.17 1998/12/31 15:29:39 warmerda
+ * Disable writing measure values to multipatch objects if
+ * DISABLE_MULTIPATCH_MEASURE is defined.
+ *
+ * Revision 1.16 1998/12/16 05:14:33 warmerda
+ * Added support to write MULTIPATCH. Fixed reading Z coordinate of
+ * MULTIPATCH. Fixed record size written for all feature types.
+ *
+ * Revision 1.15 1998/12/03 16:35:29 warmerda
+ * r+b is proper binary access string, not rb+.
+ *
+ * Revision 1.14 1998/12/03 15:47:56 warmerda
+ * Fixed setting of nVertices in SHPCreateObject().
+ *
+ * Revision 1.13 1998/12/03 15:33:54 warmerda
+ * Made SHPCalculateExtents() separately callable.
+ *
+ * Revision 1.12 1998/11/11 20:01:50 warmerda
+ * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines.
+ *
+ * Revision 1.11 1998/11/09 20:56:44 warmerda
+ * Fixed up handling of file wide bounds.
+ *
+ * Revision 1.10 1998/11/09 20:18:51 warmerda
+ * Converted to support 3D shapefiles, and use of SHPObject.
+ *
+ * Revision 1.9 1998/02/24 15:09:05 warmerda
+ * Fixed memory leak.
+ *
+ * Revision 1.8 1997/12/04 15:40:29 warmerda
+ * Fixed byte swapping of record number, and record length fields in the
+ * .shp file.
+ *
+ * Revision 1.7 1995/10/21 03:15:58 warmerda
+ * Added support for binary file access, the magic cookie 9997
+ * and tried to improve the int32 selection logic for 16bit systems.
+ *
+ * Revision 1.6 1995/09/04 04:19:41 warmerda
+ * Added fix for file bounds.
+ *
+ * Revision 1.5 1995/08/25 15:16:44 warmerda
+ * Fixed a couple of problems with big endian systems ... one with bounds
+ * and the other with multipart polygons.
+ *
+ * Revision 1.4 1995/08/24 18:10:17 warmerda
+ * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc()
+ * functions (such as on the Sun).
+ *
+ * Revision 1.3 1995/08/23 02:23:15 warmerda
+ * Added support for reading bounds, and fixed up problems in setting the
+ * file wide bounds.
+ *
+ * Revision 1.2 1995/08/04 03:16:57 warmerda
+ * Added header.
+ *
+ */
+
+static char rcsid[] =
+ "$Id: shpopen.c 2212 2004-05-17 15:47:57Z bh $";
+
+#include "shapefil.h"
+
+#include <math.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned char uchar;
+
+#if UINT_MAX == 65535
+typedef long int32;
+#else
+typedef int int32;
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE 1
+#endif
+
+#define ByteCopy( a, b, c ) memcpy( b, a, c )
+#ifndef MAX
+# define MIN(a,b) ((a<b) ? a : b)
+# define MAX(a,b) ((a>b) ? a : b)
+#endif
+
+static int bBigEndian;
+
+
+/************************************************************************/
+/* SwapWord() */
+/* */
+/* Swap a 2, 4 or 8 byte word. */
+/************************************************************************/
+
+static void SwapWord( int length, void * wordP )
+
+{
+ int i;
+ uchar temp;
+
+ for( i=0; i < length/2; i++ )
+ {
+ temp = ((uchar *) wordP)[i];
+ ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1];
+ ((uchar *) wordP)[length-i-1] = temp;
+ }
+}
+
+/************************************************************************/
+/* SfRealloc() */
+/* */
+/* A realloc cover function that will access a NULL pointer as */
+/* a valid input. */
+/************************************************************************/
+
+static void * SfRealloc( void * pMem, int nNewSize )
+
+{
+ if( pMem == NULL )
+ return( (void *) malloc(nNewSize) );
+ else
+ return( (void *) realloc(pMem,nNewSize) );
+}
+
+/************************************************************************/
+/* SHPWriteHeader() */
+/* */
+/* Write out a header for the .shp and .shx files as well as the */
+/* contents of the index (.shx) file. */
+/************************************************************************/
+
+void SHPWriteHeader( SHPHandle psSHP )
+
+{
+ uchar abyHeader[100];
+ int i;
+ int32 i32;
+ double dValue;
+ int32 *panSHX;
+
+/* -------------------------------------------------------------------- */
+/* Prepare header block for .shp file. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < 100; i++ )
+ abyHeader[i] = 0;
+
+ abyHeader[2] = 0x27; /* magic cookie */
+ abyHeader[3] = 0x0a;
+
+ i32 = psSHP->nFileSize/2; /* file size */
+ ByteCopy( &i32, abyHeader+24, 4 );
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
+
+ i32 = 1000; /* version */
+ ByteCopy( &i32, abyHeader+28, 4 );
+ if( bBigEndian ) SwapWord( 4, abyHeader+28 );
+
+ i32 = psSHP->nShapeType; /* shape type */
+ ByteCopy( &i32, abyHeader+32, 4 );
+ if( bBigEndian ) SwapWord( 4, abyHeader+32 );
+
+ dValue = psSHP->adBoundsMin[0]; /* set bounds */
+ ByteCopy( &dValue, abyHeader+36, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+36 );
+
+ dValue = psSHP->adBoundsMin[1];
+ ByteCopy( &dValue, abyHeader+44, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+44 );
+
+ dValue = psSHP->adBoundsMax[0];
+ ByteCopy( &dValue, abyHeader+52, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+52 );
+
+ dValue = psSHP->adBoundsMax[1];
+ ByteCopy( &dValue, abyHeader+60, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+60 );
+
+ dValue = psSHP->adBoundsMin[2]; /* z */
+ ByteCopy( &dValue, abyHeader+68, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+68 );
+
+ dValue = psSHP->adBoundsMax[2];
+ ByteCopy( &dValue, abyHeader+76, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+76 );
+
+ dValue = psSHP->adBoundsMin[3]; /* m */
+ ByteCopy( &dValue, abyHeader+84, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+84 );
+
+ dValue = psSHP->adBoundsMax[3];
+ ByteCopy( &dValue, abyHeader+92, 8 );
+ if( bBigEndian ) SwapWord( 8, abyHeader+92 );
+
+/* -------------------------------------------------------------------- */
+/* Write .shp file header. */
+/* -------------------------------------------------------------------- */
+ if( fseek( psSHP->fpSHP, 0, 0 ) != 0
+ || fwrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_OpenFailed,
+ "Failure writing .shp header." );
+#endif
+ return;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Prepare, and write .shx file header. */
+/* -------------------------------------------------------------------- */
+ i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
+ ByteCopy( &i32, abyHeader+24, 4 );
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
+
+ if( fseek( psSHP->fpSHX, 0, 0 ) != 0
+ || fwrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_OpenFailed,
+ "Failure writing .shx header." );
+#endif
+ return;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Write out the .shx contents. */
+/* -------------------------------------------------------------------- */
+ panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
+
+ for( i = 0; i < psSHP->nRecords; i++ )
+ {
+ panSHX[i*2 ] = psSHP->panRecOffset[i]/2;
+ panSHX[i*2+1] = psSHP->panRecSize[i]/2;
+ if( !bBigEndian ) SwapWord( 4, panSHX+i*2 );
+ if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
+ }
+
+ if( fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX )
+ != psSHP->nRecords )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_OpenFailed,
+ "Failure writing .shx contents." );
+#endif
+ }
+
+ free( panSHX );
+
+/* -------------------------------------------------------------------- */
+/* Flush to disk. */
+/* -------------------------------------------------------------------- */
+ fflush( psSHP->fpSHP );
+ fflush( psSHP->fpSHX );
+}
+
+/************************************************************************/
+/* shpopen() */
+/* */
+/* Open the .shp and .shx files based on the basename of the */
+/* files or either file name. */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPOpen( const char * pszLayer, const char * pszAccess )
+
+{
+ char *pszFullname, *pszBasename;
+ SHPHandle psSHP;
+
+ uchar *pabyBuf;
+ int i;
+ double dValue;
+
+/* -------------------------------------------------------------------- */
+/* Ensure the access string is one of the legal ones. We */
+/* ensure the result string indicates binary to avoid common */
+/* problems on Windows. */
+/* -------------------------------------------------------------------- */
+ if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
+ || strcmp(pszAccess,"r+") == 0 )
+ pszAccess = "r+b";
+ else
+ pszAccess = "rb";
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this machine. */
+/* -------------------------------------------------------------------- */
+ i = 1;
+ if( *((uchar *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Initialize the info structure. */
+/* -------------------------------------------------------------------- */
+ psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
+
+ psSHP->bUpdated = FALSE;
+
+/* -------------------------------------------------------------------- */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
+/* -------------------------------------------------------------------- */
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
+ strcpy( pszBasename, pszLayer );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
+ i-- ) {}
+
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
+
+/* -------------------------------------------------------------------- */
+/* Open the .shp and .shx files. Note that files pulled from */
+/* a PC to Unix with upper case filenames won't work! */
+/* -------------------------------------------------------------------- */
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.shp", pszBasename );
+ psSHP->fpSHP = fopen(pszFullname, pszAccess );
+ if( psSHP->fpSHP == NULL )
+ {
+ sprintf( pszFullname, "%s.SHP", pszBasename );
+ psSHP->fpSHP = fopen(pszFullname, pszAccess );
+ }
+
+ if( psSHP->fpSHP == NULL )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_OpenFailed,
+ "Unable to open %s.shp or %s.SHP.",
+ pszBasename, pszBasename );
+#endif
+ free( psSHP );
+ free( pszBasename );
+ free( pszFullname );
+ return( NULL );
+ }
+
+ sprintf( pszFullname, "%s.shx", pszBasename );
+ psSHP->fpSHX = fopen(pszFullname, pszAccess );
+ if( psSHP->fpSHX == NULL )
+ {
+ sprintf( pszFullname, "%s.SHX", pszBasename );
+ psSHP->fpSHX = fopen(pszFullname, pszAccess );
+ }
+
+ if( psSHP->fpSHX == NULL )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_OpenFailed,
+ "Unable to open %s.shx or %s.SHX.",
+ pszBasename, pszBasename );
+#endif
+ fclose( psSHP->fpSHP );
+ free( psSHP );
+ free( pszBasename );
+ free( pszFullname );
+ return( NULL );
+ }
+
+ free( pszFullname );
+ free( pszBasename );
+
+/* -------------------------------------------------------------------- */
+/* Read the file size from the SHP file. */
+/* -------------------------------------------------------------------- */
+ pabyBuf = (uchar *) malloc(100);
+ fread( pabyBuf, 100, 1, psSHP->fpSHP );
+
+ psSHP->nFileSize = (pabyBuf[24] * 256 * 256 * 256
+ + pabyBuf[25] * 256 * 256
+ + pabyBuf[26] * 256
+ + pabyBuf[27]) * 2;
+
+/* -------------------------------------------------------------------- */
+/* Read SHX file Header info */
+/* -------------------------------------------------------------------- */
+ if( fread( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
+ || pabyBuf[0] != 0
+ || pabyBuf[1] != 0
+ || pabyBuf[2] != 0x27
+ || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ ".shx file is unreadable, or corrupt." );
+#endif
+ fclose( psSHP->fpSHP );
+ fclose( psSHP->fpSHX );
+ free( psSHP );
+
+ return( NULL );
+ }
+
+ psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
+ + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
+ psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
+
+ psSHP->nShapeType = pabyBuf[32];
+
+ if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Record count in .shp header is %d, which seems\n"
+ "unreasonable. Assuming header is corrupt.",
+ psSHP->nRecords );
+#endif
+ fclose( psSHP->fpSHP );
+ fclose( psSHP->fpSHX );
+ free( psSHP );
+
+ return( NULL );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read the bounds. */
+/* -------------------------------------------------------------------- */
+ if( bBigEndian ) SwapWord( 8, pabyBuf+36 );
+ memcpy( &dValue, pabyBuf+36, 8 );
+ psSHP->adBoundsMin[0] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+44 );
+ memcpy( &dValue, pabyBuf+44, 8 );
+ psSHP->adBoundsMin[1] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+52 );
+ memcpy( &dValue, pabyBuf+52, 8 );
+ psSHP->adBoundsMax[0] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+60 );
+ memcpy( &dValue, pabyBuf+60, 8 );
+ psSHP->adBoundsMax[1] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
+ memcpy( &dValue, pabyBuf+68, 8 );
+ psSHP->adBoundsMin[2] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
+ memcpy( &dValue, pabyBuf+76, 8 );
+ psSHP->adBoundsMax[2] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
+ memcpy( &dValue, pabyBuf+84, 8 );
+ psSHP->adBoundsMin[3] = dValue;
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+92 );
+ memcpy( &dValue, pabyBuf+92, 8 );
+ psSHP->adBoundsMax[3] = dValue;
+
+ free( pabyBuf );
+
+/* -------------------------------------------------------------------- */
+/* Read the .shx file to get the offsets to each record in */
+/* the .shp file. */
+/* -------------------------------------------------------------------- */
+ psSHP->nMaxRecords = psSHP->nRecords;
+
+ psSHP->panRecOffset =
+ (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
+ psSHP->panRecSize =
+ (int *) malloc(sizeof(int) * MAX(1,psSHP->nMaxRecords) );
+
+ pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
+ if( fread( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) != psSHP->nRecords )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Failed to read all values for %d records in .shx file.",
+ psSHP->nRecords );
+#endif
+ /* SHX is short or unreadable for some reason. */
+ fclose( psSHP->fpSHP );
+ fclose( psSHP->fpSHX );
+ free( psSHP->panRecOffset );
+ free( psSHP->panRecSize );
+ free( psSHP );
+
+ return( NULL );
+ }
+
+ for( i = 0; i < psSHP->nRecords; i++ )
+ {
+ int32 nOffset, nLength;
+
+ memcpy( &nOffset, pabyBuf + i * 8, 4 );
+ if( !bBigEndian ) SwapWord( 4, &nOffset );
+
+ memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
+ if( !bBigEndian ) SwapWord( 4, &nLength );
+
+ psSHP->panRecOffset[i] = nOffset*2;
+ psSHP->panRecSize[i] = nLength*2;
+ }
+ free( pabyBuf );
+
+ return( psSHP );
+}
+
+/************************************************************************/
+/* SHPClose() */
+/* */
+/* Close the .shp and .shx files. */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPClose(SHPHandle psSHP )
+
+{
+ if( psSHP == NULL )
+ return;
+
+/* -------------------------------------------------------------------- */
+/* Update the header if we have modified anything. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->bUpdated )
+ SHPWriteHeader( psSHP );
+
+/* -------------------------------------------------------------------- */
+/* Free all resources, and close files. */
+/* -------------------------------------------------------------------- */
+ free( psSHP->panRecOffset );
+ free( psSHP->panRecSize );
+
+ fclose( psSHP->fpSHX );
+ fclose( psSHP->fpSHP );
+
+ if( psSHP->pabyRec != NULL )
+ {
+ free( psSHP->pabyRec );
+ }
+
+ free( psSHP );
+}
+
+/************************************************************************/
+/* SHPGetInfo() */
+/* */
+/* Fetch general information about the shape file. */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType,
+ double * padfMinBound, double * padfMaxBound )
+
+{
+ int i;
+
+ if( psSHP == NULL )
+ return;
+
+ if( pnEntities != NULL )
+ *pnEntities = psSHP->nRecords;
+
+ if( pnShapeType != NULL )
+ *pnShapeType = psSHP->nShapeType;
+
+ for( i = 0; i < 4; i++ )
+ {
+ if( padfMinBound != NULL )
+ padfMinBound[i] = psSHP->adBoundsMin[i];
+ if( padfMaxBound != NULL )
+ padfMaxBound[i] = psSHP->adBoundsMax[i];
+ }
+}
+
+/************************************************************************/
+/* SHPCreate() */
+/* */
+/* Create a new shape file and return a handle to the open */
+/* shape file with read/write access. */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPCreate( const char * pszLayer, int nShapeType )
+
+{
+ char *pszBasename, *pszFullname;
+ int i;
+ FILE *fpSHP, *fpSHX;
+ uchar abyHeader[100];
+ int32 i32;
+ double dValue;
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this system. */
+/* -------------------------------------------------------------------- */
+ i = 1;
+ if( *((uchar *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
+/* -------------------------------------------------------------------- */
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
+ strcpy( pszBasename, pszLayer );
+ for( i = strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
+ i-- ) {}
+
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
+
+/* -------------------------------------------------------------------- */
+/* Open the two files so we can write their headers. */
+/* -------------------------------------------------------------------- */
+ pszFullname = (char *) malloc(strlen(pszBasename) + 5);
+ sprintf( pszFullname, "%s.shp", pszBasename );
+ fpSHP = fopen(pszFullname, "wb" );
+ if( fpSHP == NULL )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Failed to create file %s.",
+ pszFullname );
+#endif
+ return( NULL );
+ }
+
+ sprintf( pszFullname, "%s.shx", pszBasename );
+ fpSHX = fopen(pszFullname, "wb" );
+ if( fpSHX == NULL )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Failed to create file %s.",
+ pszFullname );
+#endif
+ return( NULL );
+ }
+
+ free( pszFullname );
+ free( pszBasename );
+
+/* -------------------------------------------------------------------- */
+/* Prepare header block for .shp file. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < 100; i++ )
+ abyHeader[i] = 0;
+
+ abyHeader[2] = 0x27; /* magic cookie */
+ abyHeader[3] = 0x0a;
+
+ i32 = 50; /* file size */
+ ByteCopy( &i32, abyHeader+24, 4 );
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
+
+ i32 = 1000; /* version */
+ ByteCopy( &i32, abyHeader+28, 4 );
+ if( bBigEndian ) SwapWord( 4, abyHeader+28 );
+
+ i32 = nShapeType; /* shape type */
+ ByteCopy( &i32, abyHeader+32, 4 );
+ if( bBigEndian ) SwapWord( 4, abyHeader+32 );
+
+ dValue = 0.0; /* set bounds */
+ ByteCopy( &dValue, abyHeader+36, 8 );
+ ByteCopy( &dValue, abyHeader+44, 8 );
+ ByteCopy( &dValue, abyHeader+52, 8 );
+ ByteCopy( &dValue, abyHeader+60, 8 );
+
+/* -------------------------------------------------------------------- */
+/* Write .shp file header. */
+/* -------------------------------------------------------------------- */
+ if( fwrite( abyHeader, 100, 1, fpSHP ) != 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Failed to write .shp header." );
+#endif
+ return NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Prepare, and write .shx file header. */
+/* -------------------------------------------------------------------- */
+ i32 = 50; /* file size */
+ ByteCopy( &i32, abyHeader+24, 4 );
+ if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
+
+ if( fwrite( abyHeader, 100, 1, fpSHX ) != 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Failed to write .shx header." );
+#endif
+ return NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Close the files, and then open them as regular existing files. */
+/* -------------------------------------------------------------------- */
+ fclose( fpSHP );
+ fclose( fpSHX );
+
+ return( SHPOpen( pszLayer, "r+b" ) );
+}
+
+/************************************************************************/
+/* _SHPSetBounds() */
+/* */
+/* Compute a bounds rectangle for a shape, and set it into the */
+/* indicated location in the record. */
+/************************************************************************/
+
+static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape )
+
+{
+ ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 );
+ ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 );
+ ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 );
+ ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 );
+
+ if( bBigEndian )
+ {
+ SwapWord( 8, pabyRec + 0 );
+ SwapWord( 8, pabyRec + 8 );
+ SwapWord( 8, pabyRec + 16 );
+ SwapWord( 8, pabyRec + 24 );
+ }
+}
+
+/************************************************************************/
+/* SHPComputeExtents() */
+/* */
+/* Recompute the extents of a shape. Automatically done by */
+/* SHPCreateObject(). */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPComputeExtents( SHPObject * psObject )
+
+{
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* Build extents for this object. */
+/* -------------------------------------------------------------------- */
+ if( psObject->nVertices > 0 )
+ {
+ psObject->dfXMin = psObject->dfXMax = psObject->padfX[0];
+ psObject->dfYMin = psObject->dfYMax = psObject->padfY[0];
+ psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
+ psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
+ }
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
+ psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]);
+ psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]);
+ psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]);
+
+ psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]);
+ psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]);
+ psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]);
+ psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]);
+ }
+}
+
+/************************************************************************/
+/* SHPCreateObject() */
+/* */
+/* Create a shape object. It should be freed with */
+/* SHPDestroyObject(). */
+/************************************************************************/
+
+SHPObject SHPAPI_CALL1(*)
+SHPCreateObject( int nSHPType, int nShapeId, int nParts,
+ int * panPartStart, int * panPartType,
+ int nVertices, double * padfX, double * padfY,
+ double * padfZ, double * padfM )
+
+{
+ SHPObject *psObject;
+ int i, bHasM, bHasZ;
+
+ psObject = (SHPObject *) calloc(1,sizeof(SHPObject));
+ psObject->nSHPType = nSHPType;
+ psObject->nShapeId = nShapeId;
+
+/* -------------------------------------------------------------------- */
+/* Establish whether this shape type has M, and Z values. */
+/* -------------------------------------------------------------------- */
+ if( nSHPType == SHPT_ARCM
+ || nSHPType == SHPT_POINTM
+ || nSHPType == SHPT_POLYGONM
+ || nSHPType == SHPT_MULTIPOINTM )
+ {
+ bHasM = TRUE;
+ bHasZ = FALSE;
+ }
+ else if( nSHPType == SHPT_ARCZ
+ || nSHPType == SHPT_POINTZ
+ || nSHPType == SHPT_POLYGONZ
+ || nSHPType == SHPT_MULTIPOINTZ
+ || nSHPType == SHPT_MULTIPATCH )
+ {
+ bHasM = TRUE;
+ bHasZ = TRUE;
+ }
+ else
+ {
+ bHasM = FALSE;
+ bHasZ = FALSE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Capture parts. Note that part type is optional, and */
+/* defaults to ring. */
+/* -------------------------------------------------------------------- */
+ if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON
+ || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM
+ || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ
+ || nSHPType == SHPT_MULTIPATCH )
+ {
+ psObject->nParts = MAX(1,nParts);
+
+ psObject->panPartStart = (int *)
+ malloc(sizeof(int) * psObject->nParts);
+ psObject->panPartType = (int *)
+ malloc(sizeof(int) * psObject->nParts);
+
+ psObject->panPartStart[0] = 0;
+ psObject->panPartType[0] = SHPP_RING;
+
+ for( i = 0; i < nParts; i++ )
+ {
+ psObject->panPartStart[i] = panPartStart[i];
+ if( panPartType != NULL )
+ psObject->panPartType[i] = panPartType[i];
+ else
+ psObject->panPartType[i] = SHPP_RING;
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Capture vertices. Note that Z and M are optional, but X and */
+/* Y are not. */
+/* -------------------------------------------------------------------- */
+ if( nVertices > 0 )
+ {
+ psObject->padfX = (double *) calloc(sizeof(double),nVertices);
+ psObject->padfY = (double *) calloc(sizeof(double),nVertices);
+ psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
+ psObject->padfM = (double *) calloc(sizeof(double),nVertices);
+
+ assert( padfX != NULL );
+ assert( padfY != NULL );
+
+ for( i = 0; i < nVertices; i++ )
+ {
+ psObject->padfX[i] = padfX[i];
+ psObject->padfY[i] = padfY[i];
+ if( padfZ != NULL && bHasZ )
+ psObject->padfZ[i] = padfZ[i];
+ if( padfM != NULL && bHasM )
+ psObject->padfM[i] = padfM[i];
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Compute the extents. */
+/* -------------------------------------------------------------------- */
+ psObject->nVertices = nVertices;
+ SHPComputeExtents( psObject );
+
+ return( psObject );
+}
+
+/************************************************************************/
+/* SHPCreateSimpleObject() */
+/* */
+/* Create a simple (common) shape object. Destroy with */
+/* SHPDestroyObject(). */
+/************************************************************************/
+
+SHPObject SHPAPI_CALL1(*)
+SHPCreateSimpleObject( int nSHPType, int nVertices,
+ double * padfX, double * padfY,
+ double * padfZ )
+
+{
+ return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
+ nVertices, padfX, padfY, padfZ, NULL ) );
+}
+
+/************************************************************************/
+/* SHPWriteObject() */
+/* */
+/* Write out the vertices of a new structure. Note that it is */
+/* only possible to write vertices at the end of the file. */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
+
+{
+ int nRecordOffset, i, nRecordSize=0;
+ uchar *pabyRec;
+ int32 i32;
+
+ psSHP->bUpdated = TRUE;
+
+/* -------------------------------------------------------------------- */
+/* Ensure that shape object matches the type of the file it is */
+/* being written to. */
+/* -------------------------------------------------------------------- */
+ assert( psObject->nSHPType == psSHP->nShapeType
+ || psObject->nSHPType == SHPT_NULL );
+
+/* -------------------------------------------------------------------- */
+/* Ensure that -1 is used for appends. Either blow an */
+/* assertion, or if they are disabled, set the shapeid to -1 */
+/* for appends. */
+/* -------------------------------------------------------------------- */
+ assert( nShapeId == -1
+ || (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
+
+ if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
+ nShapeId = -1;
+
+/* -------------------------------------------------------------------- */
+/* Add the new entity to the in memory index. */
+/* -------------------------------------------------------------------- */
+ if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
+ {
+ psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
+
+ psSHP->panRecOffset = (int *)
+ SfRealloc(psSHP->panRecOffset,sizeof(int) * psSHP->nMaxRecords );
+ psSHP->panRecSize = (int *)
+ SfRealloc(psSHP->panRecSize,sizeof(int) * psSHP->nMaxRecords );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Initialize record. */
+/* -------------------------------------------------------------------- */
+ pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
+ + psObject->nParts * 8 + 128);
+
+/* -------------------------------------------------------------------- */
+/* Extract vertices for a Polygon or Arc. */
+/* -------------------------------------------------------------------- */
+ if( psObject->nSHPType == SHPT_POLYGON
+ || psObject->nSHPType == SHPT_POLYGONZ
+ || psObject->nSHPType == SHPT_POLYGONM
+ || psObject->nSHPType == SHPT_ARC
+ || psObject->nSHPType == SHPT_ARCZ
+ || psObject->nSHPType == SHPT_ARCM
+ || psObject->nSHPType == SHPT_MULTIPATCH )
+ {
+ int32 nPoints, nParts;
+ int i;
+
+ nPoints = psObject->nVertices;
+ nParts = psObject->nParts;
+
+ _SHPSetBounds( pabyRec + 12, psObject );
+
+ if( bBigEndian ) SwapWord( 4, &nPoints );
+ if( bBigEndian ) SwapWord( 4, &nParts );
+
+ ByteCopy( &nPoints, pabyRec + 40 + 8, 4 );
+ ByteCopy( &nParts, pabyRec + 36 + 8, 4 );
+
+ nRecordSize = 52;
+
+ /*
+ * Write part start positions.
+ */
+ ByteCopy( psObject->panPartStart, pabyRec + 44 + 8,
+ 4 * psObject->nParts );
+ for( i = 0; i < psObject->nParts; i++ )
+ {
+ if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i );
+ nRecordSize += 4;
+ }
+
+ /*
+ * Write multipatch part types if needed.
+ */
+ if( psObject->nSHPType == SHPT_MULTIPATCH )
+ {
+ memcpy( pabyRec + nRecordSize, psObject->panPartType,
+ 4*psObject->nParts );
+ for( i = 0; i < psObject->nParts; i++ )
+ {
+ if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize );
+ nRecordSize += 4;
+ }
+ }
+
+ /*
+ * Write the (x,y) vertex values.
+ */
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 );
+ ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 );
+
+ if( bBigEndian )
+ SwapWord( 8, pabyRec + nRecordSize );
+
+ if( bBigEndian )
+ SwapWord( 8, pabyRec + nRecordSize + 8 );
+
+ nRecordSize += 2 * 8;
+ }
+
+ /*
+ * Write the Z coordinates (if any).
+ */
+ if( psObject->nSHPType == SHPT_POLYGONZ
+ || psObject->nSHPType == SHPT_ARCZ
+ || psObject->nSHPType == SHPT_MULTIPATCH )
+ {
+ ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+ }
+
+ /*
+ * Write the M values, if any.
+ */
+ if( psObject->nSHPType == SHPT_POLYGONM
+ || psObject->nSHPType == SHPT_ARCM
+#ifndef DISABLE_MULTIPATCH_MEASURE
+ || psObject->nSHPType == SHPT_MULTIPATCH
+#endif
+ || psObject->nSHPType == SHPT_POLYGONZ
+ || psObject->nSHPType == SHPT_ARCZ )
+ {
+ ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Extract vertices for a MultiPoint. */
+/* -------------------------------------------------------------------- */
+ else if( psObject->nSHPType == SHPT_MULTIPOINT
+ || psObject->nSHPType == SHPT_MULTIPOINTZ
+ || psObject->nSHPType == SHPT_MULTIPOINTM )
+ {
+ int32 nPoints;
+ int i;
+
+ nPoints = psObject->nVertices;
+
+ _SHPSetBounds( pabyRec + 12, psObject );
+
+ if( bBigEndian ) SwapWord( 4, &nPoints );
+ ByteCopy( &nPoints, pabyRec + 44, 4 );
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
+ ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 );
+ }
+
+ nRecordSize = 48 + 16 * psObject->nVertices;
+
+ if( psObject->nSHPType == SHPT_MULTIPOINTZ )
+ {
+ ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+ }
+
+ if( psObject->nSHPType == SHPT_MULTIPOINTZ
+ || psObject->nSHPType == SHPT_MULTIPOINTM )
+ {
+ ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Write point. */
+/* -------------------------------------------------------------------- */
+ else if( psObject->nSHPType == SHPT_POINT
+ || psObject->nSHPType == SHPT_POINTZ
+ || psObject->nSHPType == SHPT_POINTM )
+ {
+ ByteCopy( psObject->padfX, pabyRec + 12, 8 );
+ ByteCopy( psObject->padfY, pabyRec + 20, 8 );
+
+ if( bBigEndian ) SwapWord( 8, pabyRec + 12 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
+
+ nRecordSize = 28;
+
+ if( psObject->nSHPType == SHPT_POINTZ )
+ {
+ ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+
+ if( psObject->nSHPType == SHPT_POINTZ
+ || psObject->nSHPType == SHPT_POINTM )
+ {
+ ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 );
+ if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
+ nRecordSize += 8;
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Not much to do for null geometries. */
+/* -------------------------------------------------------------------- */
+ else if( psObject->nSHPType == SHPT_NULL )
+ {
+ nRecordSize = 12;
+ }
+
+ else
+ {
+ /* unknown type */
+ assert( FALSE );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Establish where we are going to put this record. If we are */
+/* rewriting and existing record, and it will fit, then put it */
+/* back where the original came from. Otherwise write at the end. */
+/* -------------------------------------------------------------------- */
+ if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
+ {
+ if( nShapeId == -1 )
+ nShapeId = psSHP->nRecords++;
+
+ psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
+ psSHP->panRecSize[nShapeId] = nRecordSize-8;
+ psSHP->nFileSize += nRecordSize;
+ }
+ else
+ {
+ nRecordOffset = psSHP->panRecOffset[nShapeId];
+ }
+
+/* -------------------------------------------------------------------- */
+/* Set the shape type, record number, and record size. */
+/* -------------------------------------------------------------------- */
+ i32 = nShapeId+1; /* record # */
+ if( !bBigEndian ) SwapWord( 4, &i32 );
+ ByteCopy( &i32, pabyRec, 4 );
+
+ i32 = (nRecordSize-8)/2; /* record size */
+ if( !bBigEndian ) SwapWord( 4, &i32 );
+ ByteCopy( &i32, pabyRec + 4, 4 );
+
+ i32 = psObject->nSHPType; /* shape type */
+ if( bBigEndian ) SwapWord( 4, &i32 );
+ ByteCopy( &i32, pabyRec + 8, 4 );
+
+/* -------------------------------------------------------------------- */
+/* Write out record. */
+/* -------------------------------------------------------------------- */
+ if( fseek( psSHP->fpSHP, nRecordOffset, 0 ) != 0
+ || fwrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_FileIO,
+ "Error in fseek() or fwrite() writing object to .shp file." );
+#endif
+ free( pabyRec );
+ return -1;
+ }
+
+ free( pabyRec );
+
+/* -------------------------------------------------------------------- */
+/* Expand file wide bounds based on this shape. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->adBoundsMin[0] == 0.0
+ && psSHP->adBoundsMax[0] == 0.0
+ && psSHP->adBoundsMin[1] == 0.0
+ && psSHP->adBoundsMax[1] == 0.0 )
+ {
+ if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 )
+ {
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0;
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0;
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0;
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0;
+ }
+ else
+ {
+ psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
+ psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+ }
+ }
+
+ for( i = 0; i < psObject->nVertices; i++ )
+ {
+ psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
+ psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
+ psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
+ psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
+ psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
+ psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
+ psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
+ psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+ }
+
+ return( nShapeId );
+}
+
+/************************************************************************/
+/* SHPReadObject() */
+/* */
+/* Read the vertices, parts, and other non-attribute information */
+/* for one shape. */
+/************************************************************************/
+
+SHPObject SHPAPI_CALL1(*)
+SHPReadObject( SHPHandle psSHP, int hEntity )
+
+{
+ SHPObject *psShape;
+
+/* -------------------------------------------------------------------- */
+/* Validate the record/entity number. */
+/* -------------------------------------------------------------------- */
+ if( hEntity < 0 || hEntity >= psSHP->nRecords )
+ return( NULL );
+
+/* -------------------------------------------------------------------- */
+/* Ensure our record buffer is large enough. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize )
+ {
+ psSHP->nBufSize = psSHP->panRecSize[hEntity]+8;
+ psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize);
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read the record. */
+/* -------------------------------------------------------------------- */
+ if( fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0
+ || fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1,
+ psSHP->fpSHP ) != 1 )
+ {
+#ifdef USE_CPL
+ CPLError( CE_Failure, CPLE_FileIO,
+ "Error in fseek() or fread() reading object from .shp file." );
+#endif
+ return NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Allocate and minimally initialize the object. */
+/* -------------------------------------------------------------------- */
+ psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
+ psShape->nShapeId = hEntity;
+
+ memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
+ if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
+
+/* ==================================================================== */
+/* Extract vertices for a Polygon or Arc. */
+/* ==================================================================== */
+ if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC
+ || psShape->nSHPType == SHPT_POLYGONZ
+ || psShape->nSHPType == SHPT_POLYGONM
+ || psShape->nSHPType == SHPT_ARCZ
+ || psShape->nSHPType == SHPT_ARCM
+ || psShape->nSHPType == SHPT_MULTIPATCH )
+ {
+ int32 nPoints, nParts;
+ int i, nOffset;
+
+/* -------------------------------------------------------------------- */
+/* Get the X/Y bounds. */
+/* -------------------------------------------------------------------- */
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
+
+/* -------------------------------------------------------------------- */
+/* Extract part/point count, and build vertex and part arrays */
+/* to proper size. */
+/* -------------------------------------------------------------------- */
+ memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 );
+ memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 );
+
+ if( bBigEndian ) SwapWord( 4, &nPoints );
+ if( bBigEndian ) SwapWord( 4, &nParts );
+
+ psShape->nVertices = nPoints;
+ psShape->padfX = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfY = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+
+ psShape->nParts = nParts;
+ psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
+ psShape->panPartType = (int *) calloc(nParts,sizeof(int));
+
+ for( i = 0; i < nParts; i++ )
+ psShape->panPartType[i] = SHPP_RING;
+
+/* -------------------------------------------------------------------- */
+/* Copy out the part array from the record. */
+/* -------------------------------------------------------------------- */
+ memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
+ for( i = 0; i < nParts; i++ )
+ {
+ if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
+ }
+
+ nOffset = 44 + 8 + 4*nParts;
+
+/* -------------------------------------------------------------------- */
+/* If this is a multipatch, we will also have parts types. */
+/* -------------------------------------------------------------------- */
+ if( psShape->nSHPType == SHPT_MULTIPATCH )
+ {
+ memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
+ for( i = 0; i < nParts; i++ )
+ {
+ if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
+ }
+
+ nOffset += 4*nParts;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Copy out the vertices from the record. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy(psShape->padfX + i,
+ psSHP->pabyRec + nOffset + i * 16,
+ 8 );
+
+ memcpy(psShape->padfY + i,
+ psSHP->pabyRec + nOffset + i * 16 + 8,
+ 8 );
+
+ if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
+ if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
+ }
+
+ nOffset += 16*nPoints;
+
+/* -------------------------------------------------------------------- */
+/* If we have a Z coordinate, collect that now. */
+/* -------------------------------------------------------------------- */
+ if( psShape->nSHPType == SHPT_POLYGONZ
+ || psShape->nSHPType == SHPT_ARCZ
+ || psShape->nSHPType == SHPT_MULTIPATCH )
+ {
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
+
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy( psShape->padfZ + i,
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
+ }
+
+ nOffset += 16 + 8*nPoints;
+ }
+
+/* -------------------------------------------------------------------- */
+/* If we have a M measure value, then read it now. We assume */
+/* that the measure can be present for any shape if the size is */
+/* big enough, but really it will only occur for the Z shapes */
+/* (options), and the M shapes. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
+ {
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
+
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy( psShape->padfM + i,
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
+ if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
+ }
+ }
+
+ }
+
+/* ==================================================================== */
+/* Extract vertices for a MultiPoint. */
+/* ==================================================================== */
+ else if( psShape->nSHPType == SHPT_MULTIPOINT
+ || psShape->nSHPType == SHPT_MULTIPOINTM
+ || psShape->nSHPType == SHPT_MULTIPOINTZ )
+ {
+ int32 nPoints;
+ int i, nOffset;
+
+ memcpy( &nPoints, psSHP->pabyRec + 44, 4 );
+ if( bBigEndian ) SwapWord( 4, &nPoints );
+
+ psShape->nVertices = nPoints;
+ psShape->padfX = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfY = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
+ memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, psShape->padfX + i );
+ if( bBigEndian ) SwapWord( 8, psShape->padfY + i );
+ }
+
+ nOffset = 48 + 16*nPoints;
+
+/* -------------------------------------------------------------------- */
+/* Get the X/Y bounds. */
+/* -------------------------------------------------------------------- */
+ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 );
+ memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 );
+ memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 );
+ memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) );
+
+/* -------------------------------------------------------------------- */
+/* If we have a Z coordinate, collect that now. */
+/* -------------------------------------------------------------------- */
+ if( psShape->nSHPType == SHPT_MULTIPOINTZ )
+ {
+ memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
+
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy( psShape->padfZ + i,
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ + i );
+ }
+
+ nOffset += 16 + 8*nPoints;
+ }
+
+/* -------------------------------------------------------------------- */
+/* If we have a M measure value, then read it now. We assume */
+/* that the measure can be present for any shape if the size is */
+/* big enough, but really it will only occur for the Z shapes */
+/* (options), and the M shapes. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints )
+ {
+ memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
+ memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
+
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
+ if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
+
+ for( i = 0; i < nPoints; i++ )
+ {
+ memcpy( psShape->padfM + i,
+ psSHP->pabyRec + nOffset + 16 + i*8, 8 );
+ if( bBigEndian ) SwapWord( 8, psShape->padfM + i );
+ }
+ }
+ }
+
+/* ==================================================================== */
+/* Extract vertices for a point. */
+/* ==================================================================== */
+ else if( psShape->nSHPType == SHPT_POINT
+ || psShape->nSHPType == SHPT_POINTM
+ || psShape->nSHPType == SHPT_POINTZ )
+ {
+ int nOffset;
+
+ psShape->nVertices = 1;
+ psShape->padfX = (double *) calloc(1,sizeof(double));
+ psShape->padfY = (double *) calloc(1,sizeof(double));
+ psShape->padfZ = (double *) calloc(1,sizeof(double));
+ psShape->padfM = (double *) calloc(1,sizeof(double));
+
+ memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 );
+ memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 );
+
+ if( bBigEndian ) SwapWord( 8, psShape->padfX );
+ if( bBigEndian ) SwapWord( 8, psShape->padfY );
+
+ nOffset = 20 + 8;
+
+/* -------------------------------------------------------------------- */
+/* If we have a Z coordinate, collect that now. */
+/* -------------------------------------------------------------------- */
+ if( psShape->nSHPType == SHPT_POINTZ )
+ {
+ memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
+
+ if( bBigEndian ) SwapWord( 8, psShape->padfZ );
+
+ nOffset += 8;
+ }
+
+/* -------------------------------------------------------------------- */
+/* If we have a M measure value, then read it now. We assume */
+/* that the measure can be present for any shape if the size is */
+/* big enough, but really it will only occur for the Z shapes */
+/* (options), and the M shapes. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 )
+ {
+ memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
+
+ if( bBigEndian ) SwapWord( 8, psShape->padfM );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Since no extents are supplied in the record, we will apply */
+/* them from the single vertex. */
+/* -------------------------------------------------------------------- */
+ psShape->dfXMin = psShape->dfXMax = psShape->padfX[0];
+ psShape->dfYMin = psShape->dfYMax = psShape->padfY[0];
+ psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0];
+ psShape->dfMMin = psShape->dfMMax = psShape->padfM[0];
+ }
+
+ return( psShape );
+}
+
+/************************************************************************/
+/* SHPTypeName() */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+SHPTypeName( int nSHPType )
+
+{
+ switch( nSHPType )
+ {
+ case SHPT_NULL:
+ return "NullShape";
+
+ case SHPT_POINT:
+ return "Point";
+
+ case SHPT_ARC:
+ return "Arc";
+
+ case SHPT_POLYGON:
+ return "Polygon";
+
+ case SHPT_MULTIPOINT:
+ return "MultiPoint";
+
+ case SHPT_POINTZ:
+ return "PointZ";
+
+ case SHPT_ARCZ:
+ return "ArcZ";
+
+ case SHPT_POLYGONZ:
+ return "PolygonZ";
+
+ case SHPT_MULTIPOINTZ:
+ return "MultiPointZ";
+
+ case SHPT_POINTM:
+ return "PointM";
+
+ case SHPT_ARCM:
+ return "ArcM";
+
+ case SHPT_POLYGONM:
+ return "PolygonM";
+
+ case SHPT_MULTIPOINTM:
+ return "MultiPointM";
+
+ case SHPT_MULTIPATCH:
+ return "MultiPatch";
+
+ default:
+ return "UnknownShapeType";
+ }
+}
+
+/************************************************************************/
+/* SHPPartTypeName() */
+/************************************************************************/
+
+const char SHPAPI_CALL1(*)
+SHPPartTypeName( int nPartType )
+
+{
+ switch( nPartType )
+ {
+ case SHPP_TRISTRIP:
+ return "TriangleStrip";
+
+ case SHPP_TRIFAN:
+ return "TriangleFan";
+
+ case SHPP_OUTERRING:
+ return "OuterRing";
+
+ case SHPP_INNERRING:
+ return "InnerRing";
+
+ case SHPP_FIRSTRING:
+ return "FirstRing";
+
+ case SHPP_RING:
+ return "Ring";
+
+ default:
+ return "UnknownPartType";
+ }
+}
+
+/************************************************************************/
+/* SHPDestroyObject() */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPDestroyObject( SHPObject * psShape )
+
+{
+ if( psShape == NULL )
+ return;
+
+ if( psShape->padfX != NULL )
+ free( psShape->padfX );
+ if( psShape->padfY != NULL )
+ free( psShape->padfY );
+ if( psShape->padfZ != NULL )
+ free( psShape->padfZ );
+ if( psShape->padfM != NULL )
+ free( psShape->padfM );
+
+ if( psShape->panPartStart != NULL )
+ free( psShape->panPartStart );
+ if( psShape->panPartType != NULL )
+ free( psShape->panPartType );
+
+ free( psShape );
+}
+
+/************************************************************************/
+/* SHPRewindObject() */
+/* */
+/* Reset the winding of polygon objects to adhere to the */
+/* specification. */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
+
+{
+ int iOpRing, bAltered = 0;
+
+/* -------------------------------------------------------------------- */
+/* Do nothing if this is not a polygon object. */
+/* -------------------------------------------------------------------- */
+ if( psObject->nSHPType != SHPT_POLYGON
+ && psObject->nSHPType != SHPT_POLYGONZ
+ && psObject->nSHPType != SHPT_POLYGONM )
+ return 0;
+
+ if( psObject->nVertices == 0 || psObject->nParts == 0 )
+ return 0;
+
+/* -------------------------------------------------------------------- */
+/* Process each of the rings. */
+/* -------------------------------------------------------------------- */
+ for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ )
+ {
+ int bInner, iVert, nVertCount, nVertStart, iCheckRing;
+ double dfSum, dfTestX, dfTestY;
+
+/* -------------------------------------------------------------------- */
+/* Determine if this ring is an inner ring or an outer ring */
+/* relative to all the other rings. For now we assume the */
+/* first ring is outer and all others are inner, but eventually */
+/* we need to fix this to handle multiple island polygons and */
+/* unordered sets of rings. */
+/* -------------------------------------------------------------------- */
+ dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]];
+ dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]];
+
+ bInner = FALSE;
+ for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ )
+ {
+ int iEdge;
+
+ if( iCheckRing == iOpRing )
+ continue;
+
+ nVertStart = psObject->panPartStart[iCheckRing];
+
+ if( iCheckRing == psObject->nParts-1 )
+ nVertCount = psObject->nVertices
+ - psObject->panPartStart[iCheckRing];
+ else
+ nVertCount = psObject->panPartStart[iCheckRing+1]
+ - psObject->panPartStart[iCheckRing];
+
+ for( iEdge = 0; iEdge < nVertCount; iEdge++ )
+ {
+ int iNext;
+
+ if( iEdge < nVertCount-1 )
+ iNext = iEdge+1;
+ else
+ iNext = 0;
+
+ if( (psObject->padfY[iEdge+nVertStart] < dfTestY
+ && psObject->padfY[iNext+nVertStart] >= dfTestY)
+ || (psObject->padfY[iNext+nVertStart] < dfTestY
+ && psObject->padfY[iEdge+nVertStart] >= dfTestY) )
+ {
+ if( psObject->padfX[iEdge+nVertStart]
+ + (dfTestY - psObject->padfY[iEdge+nVertStart])
+ / (psObject->padfY[iNext+nVertStart]
+ - psObject->padfY[iEdge+nVertStart])
+ * (psObject->padfX[iNext+nVertStart]
+ - psObject->padfX[iEdge+nVertStart]) < dfTestX )
+ bInner = !bInner;
+ }
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Determine the current order of this ring so we will know if */
+/* it has to be reversed. */
+/* -------------------------------------------------------------------- */
+ nVertStart = psObject->panPartStart[iOpRing];
+
+ if( iOpRing == psObject->nParts-1 )
+ nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
+ else
+ nVertCount = psObject->panPartStart[iOpRing+1]
+ - psObject->panPartStart[iOpRing];
+
+ dfSum = 0.0;
+ for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ )
+ {
+ dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1]
+ - psObject->padfY[iVert] * psObject->padfX[iVert+1];
+ }
+
+ dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart]
+ - psObject->padfY[iVert] * psObject->padfX[nVertStart];
+
+/* -------------------------------------------------------------------- */
+/* Reverse if necessary. */
+/* -------------------------------------------------------------------- */
+ if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) )
+ {
+ int i;
+
+ bAltered++;
+ for( i = 0; i < nVertCount/2; i++ )
+ {
+ double dfSaved;
+
+ /* Swap X */
+ dfSaved = psObject->padfX[nVertStart+i];
+ psObject->padfX[nVertStart+i] =
+ psObject->padfX[nVertStart+nVertCount-i-1];
+ psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
+
+ /* Swap Y */
+ dfSaved = psObject->padfY[nVertStart+i];
+ psObject->padfY[nVertStart+i] =
+ psObject->padfY[nVertStart+nVertCount-i-1];
+ psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
+
+ /* Swap Z */
+ if( psObject->padfZ )
+ {
+ dfSaved = psObject->padfZ[nVertStart+i];
+ psObject->padfZ[nVertStart+i] =
+ psObject->padfZ[nVertStart+nVertCount-i-1];
+ psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
+ }
+
+ /* Swap M */
+ if( psObject->padfM )
+ {
+ dfSaved = psObject->padfM[nVertStart+i];
+ psObject->padfM[nVertStart+i] =
+ psObject->padfM[nVertStart+nVertCount-i-1];
+ psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
+ }
+ }
+ }
+ }
+
+ return bAltered;
+}
Added: packages/thuban/branches/upstream/current/libraries/shapelib/shptree.c
===================================================================
--- packages/thuban/branches/upstream/current/libraries/shapelib/shptree.c 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/shapelib/shptree.c 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,682 @@
+/******************************************************************************
+ * $Id: shptree.c 1769 2003-10-02 15:15:16Z bh $
+ *
+ * Project: Shapelib
+ * Purpose: Implementation of quadtree building and searching functions.
+ * Author: Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * This software is available under the following "MIT Style" license,
+ * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * option is discussed in more detail in shapelib.html.
+ *
+ * --
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log$
+ * Revision 1.2 2003/10/02 15:15:16 bh
+ * Update to shapelib 1.2.10
+ *
+ * Revision 1.9 2003/01/28 15:53:41 warmerda
+ * Avoid build warnings.
+ *
+ * Revision 1.8 2002/05/07 13:07:45 warmerda
+ * use qsort() - patch from Bernhard Herzog
+ *
+ * Revision 1.7 2002/01/15 14:36:07 warmerda
+ * updated email address
+ *
+ * Revision 1.6 2001/05/23 13:36:52 warmerda
+ * added use of SHPAPI_CALL
+ *
+ * Revision 1.5 1999/11/05 14:12:05 warmerda
+ * updated license terms
+ *
+ * Revision 1.4 1999/06/02 18:24:21 warmerda
+ * added trimming code
+ *
+ * Revision 1.3 1999/06/02 17:56:12 warmerda
+ * added quad'' subnode support for trees
+ *
+ * Revision 1.2 1999/05/18 19:11:11 warmerda
+ * Added example searching capability
+ *
+ * Revision 1.1 1999/05/18 17:49:20 warmerda
+ * New
+ *
+ */
+
+static char rcsid[] =
+ "$Id: shptree.c 1769 2003-10-02 15:15:16Z bh $";
+
+#include "shapefil.h"
+
+#include <math.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* If the following is 0.5, nodes will be split in half. If it */
+/* is 0.6 then each subnode will contain 60% of the parent */
+/* node, with 20% representing overlap. This can be help to */
+/* prevent small objects on a boundary from shifting too high */
+/* up the tree. */
+/* -------------------------------------------------------------------- */
+
+#define SHP_SPLIT_RATIO 0.55
+
+/************************************************************************/
+/* SfRealloc() */
+/* */
+/* A realloc cover function that will access a NULL pointer as */
+/* a valid input. */
+/************************************************************************/
+
+static void * SfRealloc( void * pMem, int nNewSize )
+
+{
+ if( pMem == NULL )
+ return( (void *) malloc(nNewSize) );
+ else
+ return( (void *) realloc(pMem,nNewSize) );
+}
+
+/************************************************************************/
+/* SHPTreeNodeInit() */
+/* */
+/* Initialize a tree node. */
+/************************************************************************/
+
+static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
+ double * padfBoundsMax )
+
+{
+ SHPTreeNode *psTreeNode;
+
+ psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
+
+ psTreeNode->nShapeCount = 0;
+ psTreeNode->panShapeIds = NULL;
+ psTreeNode->papsShapeObj = NULL;
+
+ psTreeNode->nSubNodes = 0;
+
+ if( padfBoundsMin != NULL )
+ memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 );
+
+ if( padfBoundsMax != NULL )
+ memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 );
+
+ return psTreeNode;
+}
+
+
+/************************************************************************/
+/* SHPCreateTree() */
+/************************************************************************/
+
+SHPTree SHPAPI_CALL1(*)
+SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
+ double *padfBoundsMin, double *padfBoundsMax )
+
+{
+ SHPTree *psTree;
+
+ if( padfBoundsMin == NULL && hSHP == NULL )
+ return NULL;
+
+/* -------------------------------------------------------------------- */
+/* Allocate the tree object */
+/* -------------------------------------------------------------------- */
+ psTree = (SHPTree *) malloc(sizeof(SHPTree));
+
+ psTree->hSHP = hSHP;
+ psTree->nMaxDepth = nMaxDepth;
+ psTree->nDimension = nDimension;
+
+/* -------------------------------------------------------------------- */
+/* If no max depth was defined, try to select a reasonable one */
+/* that implies approximately 8 shapes per node. */
+/* -------------------------------------------------------------------- */
+ if( psTree->nMaxDepth == 0 && hSHP != NULL )
+ {
+ int nMaxNodeCount = 1;
+ int nShapeCount;
+
+ SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
+ while( nMaxNodeCount*4 < nShapeCount )
+ {
+ psTree->nMaxDepth += 1;
+ nMaxNodeCount = nMaxNodeCount * 2;
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Allocate the root node. */
+/* -------------------------------------------------------------------- */
+ psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
+
+/* -------------------------------------------------------------------- */
+/* Assign the bounds to the root node. If none are passed in, */
+/* use the bounds of the provided file otherwise the create */
+/* function will have already set the bounds. */
+/* -------------------------------------------------------------------- */
+ if( padfBoundsMin == NULL )
+ {
+ SHPGetInfo( hSHP, NULL, NULL,
+ psTree->psRoot->adfBoundsMin,
+ psTree->psRoot->adfBoundsMax );
+ }
+
+/* -------------------------------------------------------------------- */
+/* If we have a file, insert all it's shapes into the tree. */
+/* -------------------------------------------------------------------- */
+ if( hSHP != NULL )
+ {
+ int iShape, nShapeCount;
+
+ SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
+
+ for( iShape = 0; iShape < nShapeCount; iShape++ )
+ {
+ SHPObject *psShape;
+
+ psShape = SHPReadObject( hSHP, iShape );
+ SHPTreeAddShapeId( psTree, psShape );
+ SHPDestroyObject( psShape );
+ }
+ }
+
+ return psTree;
+}
+
+/************************************************************************/
+/* SHPDestroyTreeNode() */
+/************************************************************************/
+
+static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
+
+{
+ int i;
+
+ for( i = 0; i < psTreeNode->nSubNodes; i++ )
+ {
+ if( psTreeNode->apsSubNode[i] != NULL )
+ SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
+ }
+
+ if( psTreeNode->panShapeIds != NULL )
+ free( psTreeNode->panShapeIds );
+
+ if( psTreeNode->papsShapeObj != NULL )
+ {
+ for( i = 0; i < psTreeNode->nShapeCount; i++ )
+ {
+ if( psTreeNode->papsShapeObj[i] != NULL )
+ SHPDestroyObject( psTreeNode->papsShapeObj[i] );
+ }
+
+ free( psTreeNode->papsShapeObj );
+ }
+
+ free( psTreeNode );
+}
+
+/************************************************************************/
+/* SHPDestroyTree() */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPDestroyTree( SHPTree * psTree )
+
+{
+ SHPDestroyTreeNode( psTree->psRoot );
+ free( psTree );
+}
+
+/************************************************************************/
+/* SHPCheckBoundsOverlap() */
+/* */
+/* Do the given boxes overlap at all? */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max,
+ double * padfBox2Min, double * padfBox2Max,
+ int nDimension )
+
+{
+ int iDim;
+
+ for( iDim = 0; iDim < nDimension; iDim++ )
+ {
+ if( padfBox2Max[iDim] < padfBox1Min[iDim] )
+ return FALSE;
+
+ if( padfBox1Max[iDim] < padfBox2Min[iDim] )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* SHPCheckObjectContained() */
+/* */
+/* Does the given shape fit within the indicated extents? */
+/************************************************************************/
+
+static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
+ double * padfBoundsMin, double * padfBoundsMax )
+
+{
+ if( psObject->dfXMin < padfBoundsMin[0]
+ || psObject->dfXMax > padfBoundsMax[0] )
+ return FALSE;
+
+ if( psObject->dfYMin < padfBoundsMin[1]
+ || psObject->dfYMax > padfBoundsMax[1] )
+ return FALSE;
+
+ if( nDimension == 2 )
+ return TRUE;
+
+ if( psObject->dfZMin < padfBoundsMin[2]
+ || psObject->dfZMax < padfBoundsMax[2] )
+ return FALSE;
+
+ if( nDimension == 3 )
+ return TRUE;
+
+ if( psObject->dfMMin < padfBoundsMin[3]
+ || psObject->dfMMax < padfBoundsMax[3] )
+ return FALSE;
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* SHPTreeSplitBounds() */
+/* */
+/* Split a region into two subregion evenly, cutting along the */
+/* longest dimension. */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
+ double *padfBoundsMin1, double * padfBoundsMax1,
+ double *padfBoundsMin2, double * padfBoundsMax2 )
+
+{
+/* -------------------------------------------------------------------- */
+/* The output bounds will be very similar to the input bounds, */
+/* so just copy over to start. */
+/* -------------------------------------------------------------------- */
+ memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 );
+ memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 );
+ memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 );
+ memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 );
+
+/* -------------------------------------------------------------------- */
+/* Split in X direction. */
+/* -------------------------------------------------------------------- */
+ if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0])
+ > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) )
+ {
+ double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0];
+
+ padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO;
+ padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Otherwise split in Y direction. */
+/* -------------------------------------------------------------------- */
+ else
+ {
+ double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1];
+
+ padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO;
+ padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO;
+ }
+}
+
+/************************************************************************/
+/* SHPTreeNodeAddShapeId() */
+/************************************************************************/
+
+static int
+SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
+ int nMaxDepth, int nDimension )
+
+{
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* If there are subnodes, then consider wiether this object */
+/* will fit in them. */
+/* -------------------------------------------------------------------- */
+ if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 )
+ {
+ for( i = 0; i < psTreeNode->nSubNodes; i++ )
+ {
+ if( SHPCheckObjectContained(psObject, nDimension,
+ psTreeNode->apsSubNode[i]->adfBoundsMin,
+ psTreeNode->apsSubNode[i]->adfBoundsMax))
+ {
+ return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i],
+ psObject, nMaxDepth-1,
+ nDimension );
+ }
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Otherwise, consider creating four subnodes if could fit into */
+/* them, and adding to the appropriate subnode. */
+/* -------------------------------------------------------------------- */
+#if MAX_SUBNODE == 4
+ else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
+ {
+ double adfBoundsMinH1[4], adfBoundsMaxH1[4];
+ double adfBoundsMinH2[4], adfBoundsMaxH2[4];
+ double adfBoundsMin1[4], adfBoundsMax1[4];
+ double adfBoundsMin2[4], adfBoundsMax2[4];
+ double adfBoundsMin3[4], adfBoundsMax3[4];
+ double adfBoundsMin4[4], adfBoundsMax4[4];
+
+ SHPTreeSplitBounds( psTreeNode->adfBoundsMin,
+ psTreeNode->adfBoundsMax,
+ adfBoundsMinH1, adfBoundsMaxH1,
+ adfBoundsMinH2, adfBoundsMaxH2 );
+
+ SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1,
+ adfBoundsMin1, adfBoundsMax1,
+ adfBoundsMin2, adfBoundsMax2 );
+
+ SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2,
+ adfBoundsMin3, adfBoundsMax3,
+ adfBoundsMin4, adfBoundsMax4 );
+
+ if( SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin1, adfBoundsMax1)
+ || SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin2, adfBoundsMax2)
+ || SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin3, adfBoundsMax3)
+ || SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin4, adfBoundsMax4) )
+ {
+ psTreeNode->nSubNodes = 4;
+ psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
+ adfBoundsMax1 );
+ psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
+ adfBoundsMax2 );
+ psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3,
+ adfBoundsMax3 );
+ psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4,
+ adfBoundsMax4 );
+
+ /* recurse back on this node now that it has subnodes */
+ return( SHPTreeNodeAddShapeId( psTreeNode, psObject,
+ nMaxDepth, nDimension ) );
+ }
+ }
+#endif /* MAX_SUBNODE == 4 */
+
+/* -------------------------------------------------------------------- */
+/* Otherwise, consider creating two subnodes if could fit into */
+/* them, and adding to the appropriate subnode. */
+/* -------------------------------------------------------------------- */
+#if MAX_SUBNODE == 2
+ else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
+ {
+ double adfBoundsMin1[4], adfBoundsMax1[4];
+ double adfBoundsMin2[4], adfBoundsMax2[4];
+
+ SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax,
+ adfBoundsMin1, adfBoundsMax1,
+ adfBoundsMin2, adfBoundsMax2 );
+
+ if( SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin1, adfBoundsMax1))
+ {
+ psTreeNode->nSubNodes = 2;
+ psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
+ adfBoundsMax1 );
+ psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
+ adfBoundsMax2 );
+
+ return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject,
+ nMaxDepth - 1, nDimension ) );
+ }
+ else if( SHPCheckObjectContained(psObject, nDimension,
+ adfBoundsMin2, adfBoundsMax2) )
+ {
+ psTreeNode->nSubNodes = 2;
+ psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
+ adfBoundsMax1 );
+ psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
+ adfBoundsMax2 );
+
+ return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject,
+ nMaxDepth - 1, nDimension ) );
+ }
+ }
+#endif /* MAX_SUBNODE == 2 */
+
+/* -------------------------------------------------------------------- */
+/* If none of that worked, just add it to this nodes list. */
+/* -------------------------------------------------------------------- */
+ psTreeNode->nShapeCount++;
+
+ psTreeNode->panShapeIds =
+ SfRealloc( psTreeNode->panShapeIds,
+ sizeof(int) * psTreeNode->nShapeCount );
+ psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
+
+ if( psTreeNode->papsShapeObj != NULL )
+ {
+ psTreeNode->papsShapeObj =
+ SfRealloc( psTreeNode->papsShapeObj,
+ sizeof(void *) * psTreeNode->nShapeCount );
+ psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL;
+ }
+
+ return TRUE;
+}
+
+/************************************************************************/
+/* SHPTreeAddShapeId() */
+/* */
+/* Add a shape to the tree, but don't keep a pointer to the */
+/* object data, just keep the shapeid. */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
+
+{
+ return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject,
+ psTree->nMaxDepth, psTree->nDimension ) );
+}
+
+/************************************************************************/
+/* SHPTreeCollectShapesIds() */
+/* */
+/* Work function implementing SHPTreeFindLikelyShapes() on a */
+/* tree node by tree node basis. */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
+ double * padfBoundsMin, double * padfBoundsMax,
+ int * pnShapeCount, int * pnMaxShapes,
+ int ** ppanShapeList )
+
+{
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* Does this node overlap the area of interest at all? If not, */
+/* return without adding to the list at all. */
+/* -------------------------------------------------------------------- */
+ if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin,
+ psTreeNode->adfBoundsMax,
+ padfBoundsMin,
+ padfBoundsMax,
+ hTree->nDimension ) )
+ return;
+
+/* -------------------------------------------------------------------- */
+/* Grow the list to hold the shapes on this node. */
+/* -------------------------------------------------------------------- */
+ if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes )
+ {
+ *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20;
+ *ppanShapeList = (int *)
+ SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes);
+ }
+
+/* -------------------------------------------------------------------- */
+/* Add the local nodes shapeids to the list. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < psTreeNode->nShapeCount; i++ )
+ {
+ (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i];
+ }
+
+/* -------------------------------------------------------------------- */
+/* Recurse to subnodes if they exist. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < psTreeNode->nSubNodes; i++ )
+ {
+ if( psTreeNode->apsSubNode[i] != NULL )
+ SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i],
+ padfBoundsMin, padfBoundsMax,
+ pnShapeCount, pnMaxShapes,
+ ppanShapeList );
+ }
+}
+
+/************************************************************************/
+/* SHPTreeFindLikelyShapes() */
+/* */
+/* Find all shapes within tree nodes for which the tree node */
+/* bounding box overlaps the search box. The return value is */
+/* an array of shapeids terminated by a -1. The shapeids will */
+/* be in order, as hopefully this will result in faster (more */
+/* sequential) reading from the file. */
+/************************************************************************/
+
+/* helper for qsort */
+static int
+compare_ints( const void * a, const void * b)
+{
+ return (*(int*)a) - (*(int*)b);
+}
+
+int SHPAPI_CALL1(*)
+SHPTreeFindLikelyShapes( SHPTree * hTree,
+ double * padfBoundsMin, double * padfBoundsMax,
+ int * pnShapeCount )
+
+{
+ int *panShapeList=NULL, nMaxShapes = 0;
+
+/* -------------------------------------------------------------------- */
+/* Perform the search by recursive descent. */
+/* -------------------------------------------------------------------- */
+ *pnShapeCount = 0;
+
+ SHPTreeCollectShapeIds( hTree, hTree->psRoot,
+ padfBoundsMin, padfBoundsMax,
+ pnShapeCount, &nMaxShapes,
+ &panShapeList );
+
+/* -------------------------------------------------------------------- */
+/* Sort the id array */
+/* -------------------------------------------------------------------- */
+
+ qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
+
+ return panShapeList;
+}
+
+/************************************************************************/
+/* SHPTreeNodeTrim() */
+/* */
+/* This is the recurve version of SHPTreeTrimExtraNodes() that */
+/* walks the tree cleaning it up. */
+/************************************************************************/
+
+static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode )
+
+{
+ int i;
+
+/* -------------------------------------------------------------------- */
+/* Trim subtrees, and free subnodes that come back empty. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < psTreeNode->nSubNodes; i++ )
+ {
+ if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) )
+ {
+ SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
+
+ psTreeNode->apsSubNode[i] =
+ psTreeNode->apsSubNode[psTreeNode->nSubNodes-1];
+
+ psTreeNode->nSubNodes--;
+
+ i--; /* process the new occupant of this subnode entry */
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* We should be trimmed if we have no subnodes, and no shapes. */
+/* -------------------------------------------------------------------- */
+ return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 );
+}
+
+/************************************************************************/
+/* SHPTreeTrimExtraNodes() */
+/* */
+/* Trim empty nodes from the tree. Note that we never trim an */
+/* empty root node. */
+/************************************************************************/
+
+void SHPAPI_CALL
+SHPTreeTrimExtraNodes( SHPTree * hTree )
+
+{
+ SHPTreeNodeTrim( hTree->psRoot );
+}
+
Added: packages/thuban/branches/upstream/current/libraries/thuban/gdalwarp.cpp
===================================================================
--- packages/thuban/branches/upstream/current/libraries/thuban/gdalwarp.cpp 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/thuban/gdalwarp.cpp 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1232 @@
+/******************************************************************************
+ * $Id: gdalwarp.cpp 2712 2006-10-15 23:27:05Z bernhard $
+ *
+ * Project: High Performance Image Reprojector
+ * Purpose: Test program for high performance warper API.
+ * Author: Frank Warmerdam <warmerdam at pobox.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, i3 - information integration and imaging
+ * Fort Collin, CO
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log$
+ * Revision 1.9 2005/02/18 21:22:53 jonathan
+ * Optimize the loop in gdalwarp which builds a mask. Handle the majority of an
+ * image in a loop, creating 8 bits at a time. Later, handle the edge case where
+ * less than 8 bits are packed.
+ *
+ * Revision 1.8 2005/02/18 14:54:17 jonathan
+ * Refactored baserenderer.py and renderer.py to remove baserenderer.py's
+ * dependencies on wxPython. Added a new method projected_raster_layer()
+ * that returns a raster layer image in projected space. This must be
+ * implemented in classes derived from BaseRenderer. This also eliminates
+ * the dependency on gdal in baserenderer.py.
+ *
+ * Revision 1.7 2005/02/16 21:14:47 jonathan
+ * Further wxPython 2.5 changes using patches from Daniel Calvelo Aros
+ * so that that wxproj doesn't crash. Added GUI support for selecting
+ * alpha channel (opacity can't be selected yet).
+ *
+ * Revision 1.6 2005/02/07 19:51:13 jonathan
+ * Removed unnecessary/unused macros.
+ *
+ * Revision 1.5 2005/01/28 19:10:07 jonathan
+ * Recoded how the mask is packed into the bit array.
+ *
+ * Revision 1.4 2005/01/28 15:54:00 jonathan
+ * Make layer's use_mask flag default to true. Support a bit array describing
+ * the mask to use. Improve error handling in ProjectRasterFile (also addresses
+ * RT #2947).
+ *
+ * Revision 1.3 2005/01/27 14:17:01 jonathan
+ * Replace the old gdalwarp.cpp code with the non-simple version supplied with
+ * gdal. This allows added features such as creating an alpha band.
+ *
+ * Revision 1.13 2004/11/14 04:57:04 fwarmerdam
+ * added -srcalpha switch, and automatic alpha detection
+ *
+ * Revision 1.12 2004/11/05 06:15:08 fwarmerdam
+ * Don't double free the warpoptions array.
+ *
+ * Revision 1.11 2004/11/05 05:53:43 fwarmerdam
+ * Avoid various memory leaks.
+ *
+ * Revision 1.10 2004/10/07 15:53:42 fwarmerdam
+ * added preliminary alpha band support
+ *
+ * Revision 1.9 2004/08/31 19:58:57 warmerda
+ * Added error check if dst srs given but no source srs available.
+ * http://208.24.120.44/show_bug.cgi?id=603
+ *
+ * Revision 1.8 2004/08/11 21:10:29 warmerda
+ * Removed extra dumpopendatasets call.
+ *
+ * Revision 1.7 2004/08/11 20:11:24 warmerda
+ * Added special VRT mode
+ *
+ * Revision 1.6 2004/07/28 17:56:00 warmerda
+ * use return instead of exit() to avoid lame warnings on windows
+ *
+ * Revision 1.5 2004/04/02 17:33:22 warmerda
+ * added GDALGeneralCmdLineProcessor()
+ *
+ * Revision 1.4 2004/04/01 19:51:18 warmerda
+ * Added the -dstnodata commandline switch.
+ *
+ * Revision 1.3 2004/03/17 05:49:26 warmerda
+ * Fixed assert check in GDALWarpCreateOutput().
+ *
+ * Revision 1.2 2003/09/19 17:52:21 warmerda
+ * removed planned -gcp option
+ *
+ * Revision 1.1 2003/09/19 17:40:46 warmerda
+ * Renamed from gdalwarptest.cpp to gdalwarp.cpp, replacing old gdalwarp.
+ *
+ * Revision 1.12 2003/07/04 11:53:14 dron
+ * Added `-rcs' option to select bicubic B-spline resampling.
+ *
+ * Revision 1.11 2003/06/05 16:55:42 warmerda
+ * enable INIT_DEST=0 by default when creating new files
+ *
+ * Revision 1.10 2003/05/28 18:18:43 warmerda
+ * added -q (quiet) flag
+ *
+ * Revision 1.9 2003/05/21 14:40:40 warmerda
+ * fix error message
+ *
+ * Revision 1.8 2003/05/20 18:35:38 warmerda
+ * added error reporting if SRS import fails
+ *
+ * Revision 1.7 2003/05/06 18:11:29 warmerda
+ * added -multi in usage
+ *
+ * Revision 1.6 2003/04/23 05:18:02 warmerda
+ * added -multi switch
+ *
+ * Revision 1.5 2003/04/21 17:21:04 warmerda
+ * Fixed -wm switch.
+ *
+ * Revision 1.4 2003/03/28 17:43:04 warmerda
+ * added -wm option to control warp memory
+ *
+ * Revision 1.3 2003/03/18 17:37:44 warmerda
+ * add color table copying
+ *
+ * Revision 1.2 2003/03/02 05:24:02 warmerda
+ * added -srcnodata option
+ *
+ * Revision 1.1 2003/02/22 02:03:41 warmerda
+ * New
+ *
+ */
+
+#include <locale.h>
+
+#include <Python.h>
+
+#include "gdal.h"
+#include "gdal_alg.h"
+#include "gdal_priv.h"
+#include "gdalwarper.h"
+#include "cpl_string.h"
+#include "ogr_srs_api.h"
+
+#define PYTHON_CPL_ERR(x) \
+ {const char *str = CPLGetLastErrorMsg(); \
+ str != NULL ? PyErr_SetString(x, str) : PyErr_SetString(x, "");}
+
+#define LEAVE_NOW(e) { err = e; goto getOut; }
+
+#define OPTS_MASK 1
+#define OPTS_ALPHA 2
+#define OPTS_INVERT_MASK_BITS 4
+
+CPL_CVSID("$Id: gdalwarp.cpp 2712 2006-10-15 23:27:05Z bernhard $");
+
+static GDALDatasetH
+GDALWarpCreateOutput( GDALDatasetH hSrcDS, const char *pszFilename,
+ const char *pszFormat, const char *pszSourceSRS,
+ const char *pszTargetSRS, int nOrder,
+ char **papszCreateOptions, GDALDataType eDT );
+static PyObject* get_gdal_version(PyObject *, PyObject * args);
+static PyObject* ProjectRasterFile(PyObject *, PyObject * args);
+
+static double dfMinX=0.0, dfMinY=0.0, dfMaxX=0.0, dfMaxY=0.0;
+static double dfXRes=0.0, dfYRes=0.0;
+static int nForcePixels=0, nForceLines=0;
+static int bEnableDstAlpha = FALSE, bEnableSrcAlpha = FALSE;
+static int bMakeMask, bMakeAlpha, bInvertMask;
+const char *pszSrcFilename = NULL, *pszDstFilename = "MEM:::";
+
+static PyMethodDef gdalwarp_methods[] = {
+ { "ProjectRasterFile", ProjectRasterFile, METH_VARARGS },
+ { "get_gdal_version", get_gdal_version, METH_VARARGS },
+ {NULL, NULL}
+};
+
+/************************************************************************/
+/* get_gdal_version */
+/************************************************************************/
+static PyObject*
+get_gdal_version(PyObject *, PyObject * args)
+{
+ PyObject *version = PyString_FromString(GDALVersionInfo("RELEASE_NAME"));
+
+ Py_XINCREF(version);
+
+ return version;
+}
+
+/************************************************************************/
+/* initgdalwarp */
+/************************************************************************/
+#ifdef __cplusplus
+extern "C"
+#endif
+void initgdalwarp(void)
+{
+ PyObject * shapelib = NULL;
+ PyObject * c_api_func = NULL;
+ PyObject * cobj = NULL;
+
+ Py_InitModule("gdalwarp", gdalwarp_methods);
+
+ Py_XDECREF(cobj);
+ Py_XDECREF(c_api_func);
+ Py_XDECREF(shapelib);
+}
+
+/************************************************************************/
+/* SanitizeSRS */
+/************************************************************************/
+
+char *SanitizeSRS( const char *pszUserInput )
+
+{
+ OGRSpatialReferenceH hSRS;
+ char *pszResult = NULL;
+
+ CPLErrorReset();
+
+ hSRS = OSRNewSpatialReference( NULL );
+ if( OSRSetFromUserInput( hSRS, pszUserInput ) == OGRERR_NONE )
+ OSRExportToWkt( hSRS, &pszResult );
+#if 0
+ else
+ {
+ CPLError( CE_Failure, CPLE_AppDefined,
+ "Translating source or target SRS failed:\n%s",
+ pszUserInput );
+ exit( 1 );
+ }
+#endif
+
+ OSRDestroySpatialReference( hSRS );
+
+ return pszResult;
+}
+
+/************************************************************************/
+/* GetImageData */
+/* */
+/* Extract the image data from the GDALDataset and pack it into a single*/
+/* array of RGB triples. Use the ColorTable to determine the RGB */
+/* values. We extract the data from the GDALDataset rather than create */
+/* our own driver because the data needs to be translated from */
+/* 4 byte pixel information into 3 byte RGB information. This could be */
+/* done as the data is written to the data set or afterwards, as it is */
+/* done here. Any minor savings from our own driver are outweighed by */
+/* the high development/maintenance costs. */
+/* */
+/************************************************************************/
+
+static CPLErr GetImageData(GDALDataset *ds,
+ unsigned char **imgbuf,
+ unsigned int *imglen,
+ unsigned char **maskbuf,
+ unsigned int *masklen)
+{
+ CPLErr ret = CE_None;
+
+ GDALColorTable *pal = NULL;
+
+
+ ds->FlushCache();
+
+ int rasterCount = ds->GetRasterCount();
+ int nRasterXSize = ds->GetRasterXSize();
+ int nRasterYSize = ds->GetRasterYSize();
+ if ( ! (nRasterXSize > 0 && nRasterYSize > 0 ))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "The dimensions (%ix%i) are invalid in %s",
+ nRasterXSize, nRasterYSize, pszSrcFilename);
+ return CE_Failure;
+ }
+
+ //
+ // create the new image array for RGBRGB... values
+ //
+ *imglen = 3 * nRasterXSize * nRasterYSize;
+ *imgbuf = (unsigned char*)CPLMalloc(*imglen);
+ if ( *imgbuf == NULL )
+ {
+ PyErr_Format(PyExc_MemoryError,
+ "The system does not have enough memory to project %s",
+ pszSrcFilename);
+ return CE_Failure;
+ }
+
+ //
+ // if there are three or more bands assume that the first three
+ // are for RGB, unless told otherwise
+ //
+ if (rasterCount >= 3)
+ {
+ for (int i=1; i <= 3; i++)
+ {
+ int offs = 0;
+ GDALRasterBand *band = ds->GetRasterBand(i);
+
+ switch (band->GetColorInterpretation())
+ {
+ case GCI_Undefined: offs = i-1; break;
+ case GCI_RedBand: offs = 1; break;
+ case GCI_GreenBand: offs = 2; break;
+ case GCI_BlueBand: offs = 3; break;
+ default: offs = -1; break;
+ }
+
+ //
+ // copy the image into the buffer using the proper offset
+ // so we first copy over all Red values, then all Green
+ // values, and then all Blue values
+ //
+
+ if (0 <= offs && offs < 3)
+ {
+ ret = band->RasterIO(GF_Read, 0, 0,
+ nRasterXSize, nRasterYSize,
+ *imgbuf+offs, nRasterXSize, nRasterYSize,
+ GDT_Byte, 3, 0);
+ if (ret == CE_Failure)
+ {
+ PyErr_Format(PyExc_IOError,
+ "An unknown error occured while reading band %i in %s",
+ i, pszSrcFilename);
+ break;
+ }
+ }
+ }
+ }
+ else if (rasterCount >= 1)
+ {
+ //
+ // one band is either a palette based image, or greyscale
+ //
+
+ GDALRasterBand *band = ds->GetRasterBand(1);
+
+ switch (band->GetColorInterpretation())
+ {
+ case GCI_PaletteIndex:
+
+ pal = band->GetColorTable();
+
+ if (pal == NULL)
+ {
+ PyErr_Format(PyExc_IOError,
+ "Couldn't find a palette for palette-based image %s",
+ pszSrcFilename);
+ ret = CE_Failure;
+ }
+ else
+ {
+ GDALPaletteInterp pal_interp
+ = pal->GetPaletteInterpretation();
+
+ //
+ // copy over all the palette indices and then
+ // loop through the buffer replacing the values
+ // with the correct RGB triples.
+ //
+ ret = band->RasterIO(GF_Read, 0, 0,
+ nRasterXSize, nRasterYSize,
+ *imgbuf, nRasterXSize, nRasterYSize,
+ GDT_UInt16, 3, 0);
+
+ if (ret == CE_Failure)
+ {
+ PyErr_Format(PyExc_IOError,
+ "An unknown error occured while reading band 1 in %s", pszSrcFilename);
+ break;
+ }
+
+ for (unsigned char *data = *imgbuf;
+ data != (*imgbuf+*imglen);
+ data += 3)
+ {
+
+ unsigned short int val = *((unsigned short int *)data);
+
+ const GDALColorEntry *color = pal->GetColorEntry(val);
+
+ if (pal_interp == GPI_Gray)
+ {
+ *(data + 0) = color->c1;
+ *(data + 1) = color->c1;
+ *(data + 2) = color->c1;
+ }
+ else
+ {
+ *(data + 0) = color->c1;
+ *(data + 1) = color->c2;
+ *(data + 2) = color->c3;
+ }
+ }
+ }
+ break;
+
+ case GCI_Undefined: // can we try to make a greyscale image?
+ case GCI_GrayIndex:
+
+ //
+ // copy over all the palette indices and then
+ // loop through the buffer replacing the values
+ // with the correct RGB triples.
+ //
+ ret = band->RasterIO(GF_Read, 0, 0,
+ nRasterXSize, nRasterYSize,
+ *imgbuf, nRasterXSize, nRasterYSize,
+ GDT_Byte, 3, 0);
+
+ if (ret == CE_Failure)
+ {
+ PyErr_Format(PyExc_IOError,
+ "An unknown error occured while reading band 1 in %s",
+ pszSrcFilename);
+ break;
+ }
+
+ for (unsigned char *data = *imgbuf;
+ data != (*imgbuf+*imglen);
+ data += 3)
+ {
+ //pal->GetColorEntry(*data, &color);
+
+ //*(data + 0) = *data; // already correct
+ *(data + 1) = *data;
+ *(data + 2) = *data;
+ }
+ break;
+
+ default:
+ PyErr_Format(PyExc_ValueError,
+ "Unsupported color interpretation '%s' in image %s",
+ GDALGetColorInterpretationName(
+ band->GetColorInterpretation()),
+ pszSrcFilename);
+
+ ret = CE_Failure;
+ break;
+ }
+ }
+ else
+ {
+ PyErr_Format(PyExc_ValueError,
+ "Unsupported number of raster bands (%i) in image %s\n",
+ rasterCount, pszSrcFilename);
+
+ ret = CE_Failure;
+ }
+
+ if (ret == CE_None && bEnableDstAlpha && rasterCount > 1)
+ {
+ if (bMakeMask)
+ {
+ //
+ // The mask is really an XBM image. In other words, each
+ // pixel is represented by one bit in a byte array.
+ //
+ // First read the alpha band, and then convert it to
+ // a bit array by thresholding each pixel value at 128.
+ //
+
+ *masklen = ((nRasterXSize + 7) / 8) * nRasterYSize;
+ *maskbuf = (unsigned char *)CPLMalloc(*masklen);
+
+ if ( *maskbuf != NULL )
+ {
+ unsigned char *tmp
+ = (unsigned char *)CPLMalloc(nRasterXSize * nRasterYSize);
+
+ if ( tmp == NULL )
+ {
+ CPLFree(*maskbuf);
+ *maskbuf = NULL;
+ }
+ else
+ {
+ GDALRasterBand *band = ds->GetRasterBand(rasterCount);
+
+ ret = band->RasterIO(GF_Read, 0, 0,
+ nRasterXSize, nRasterYSize,
+ tmp, nRasterXSize, nRasterYSize,
+ GDT_Byte, 0, 0);
+
+ if (ret != CE_Failure)
+ {
+ int i, j, b=1, c=0;
+ unsigned char *ptr = *maskbuf;
+ unsigned char *tptr = tmp;
+
+ //unsigned int empty_count=0;
+
+ for (i=0; i < nRasterYSize; i++)
+ {
+ for (j=nRasterXSize; j >= 8; j -= 8)
+ {
+ c=0; b=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+ if (*tptr++ >= 128) {c|=b;} b<<=1;
+
+ if (bInvertMask)
+ *(ptr++) = ~c;
+ else
+ *(ptr++) = c;
+ }
+
+ c=0; b=1;
+ switch (nRasterXSize & 7)
+ {
+ case 7: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 6: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 5: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 4: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 3: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 2: if (*tptr++ >= 128) {c|=b;} b<<=1;
+ case 1:
+ if (*tptr++ >= 128) {c|=b;}
+ b<<=1;
+
+ //
+ // byte should be padded with 0's so
+ // it's not a simple inversion
+ //
+ if (bInvertMask)
+ *(ptr++) = ~c & (b-1);
+ else
+ *(ptr++) = c;
+
+ default: break;
+ }
+ }
+
+#if 0
+ if (empty_count == *masklen)
+ {
+ fprintf(stderr, "mask not used\n");
+
+ CPLFree(*maskbuf);
+ *maskbuf = NULL;
+ }
+#endif
+ }
+
+ CPLFree(tmp);
+ tmp = NULL;
+ }
+
+ }
+ }
+ else if (bMakeAlpha)
+ {
+ //
+ // This is the simple case. The array we get back from RasterIO
+ // is already in the correct format.
+ //
+
+ *masklen = nRasterXSize * nRasterYSize;
+ *maskbuf = (unsigned char *)CPLMalloc(*masklen);
+
+ if ( *maskbuf != NULL )
+ {
+ GDALRasterBand *band = ds->GetRasterBand(rasterCount);
+
+ ret = band->RasterIO(GF_Read, 0, 0,
+ nRasterXSize, nRasterYSize,
+ *maskbuf, nRasterXSize, nRasterYSize,
+ GDT_Byte, 0, 0);
+
+#if 0
+ if (ret == CE_Failure)
+ {
+ CPLFree(*maskbuf);
+ *maskbuf = NULL;
+ }
+#endif
+ }
+ }
+ }
+
+ if (ret != CE_None)
+ {
+ if (*imgbuf != NULL) { CPLFree(*imgbuf); *imgbuf = NULL; }
+ if (*maskbuf != NULL) { CPLFree(*maskbuf); *maskbuf = NULL; }
+ }
+
+ return ret;
+}
+
+/************************************************************************/
+/* ProjectRasterFile */
+/************************************************************************/
+
+static PyObject*
+ProjectRasterFile(PyObject *, PyObject * args)
+{
+ GDALDatasetH hSrcDS=NULL, hDstDS=NULL;
+ const char *pszFormat = "MEM";
+ char *pszTargetSRS = NULL;
+ char *pszSourceSRS = NULL;
+ int bCreateOutput = FALSE, i, nOrder = 0;
+ void *hTransformArg, *hGenImgProjArg=NULL, *hApproxArg=NULL;
+ char **papszWarpOptions = NULL;
+ double dfErrorThreshold = 0.125;
+ double dfWarpMemoryLimit = 0.0;
+ GDALTransformerFunc pfnTransformer = NULL;
+ char **papszCreateOptions = NULL;
+ GDALDataType eOutputType = GDT_Unknown, eWorkingType = GDT_Unknown;
+ GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
+ int bMulti = FALSE;
+ int err = 0;
+ unsigned char *imgbuf = NULL;
+ unsigned int imglen = 0;
+ unsigned char *maskbuf = NULL;
+ unsigned int masklen = 0;
+ int options = 0;
+
+ char * savedlocale = NULL;
+
+ GDALWarpOperation oWO;
+ GDALWarpOptions *psWO = NULL;
+
+ PyObject * pyImageData = NULL;
+ PyObject * pyMaskData = NULL;
+ PyObject * filename;
+ PyObject * srcImageArgs;
+ PyObject * dstImageArgs;
+ PyObject * extents;
+ PyObject * resolution;
+ PyObject * imageRes;
+ PyObject * opts;
+ PyObject * pyReturnData = NULL;
+
+
+ if (!PyArg_ParseTuple(args, "OOOOOOO", &filename, &srcImageArgs,
+ &dstImageArgs,
+ &extents,
+ &resolution, &imageRes,
+ &opts))
+ {
+ return NULL;
+ }
+
+ dfXRes=0.0; dfYRes=0.0;
+
+ pszSrcFilename = PyString_AsString( filename );
+
+# if PY_VERSION_HEX >=0x02040000
+ /* python before 2.4 only called modules with LC_NUMERIC "C".
+ * so we only need to act for >=2.4 */
+ savedlocale = setlocale( LC_NUMERIC, NULL );
+ if (! setlocale( LC_NUMERIC, "C" ))
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Could not switch to locale \"C\".");
+ /* did not open anything, so no need to jump to getOut */
+ return NULL;
+ }
+# endif
+
+ pszSourceSRS = SanitizeSRS( PyString_AsString( srcImageArgs ) );
+ pszTargetSRS = SanitizeSRS( PyString_AsString( dstImageArgs ) );
+
+ dfMinX = PyFloat_AsDouble( PyTuple_GetItem( extents, 0 ) );
+ dfMinY = PyFloat_AsDouble( PyTuple_GetItem( extents, 1 ) );
+ dfMaxX = PyFloat_AsDouble( PyTuple_GetItem( extents, 2 ) );
+ dfMaxY = PyFloat_AsDouble( PyTuple_GetItem( extents, 3 ) );
+
+ nForcePixels = ( int )PyInt_AsLong( PyTuple_GetItem( imageRes, 0 ) );
+ nForceLines = ( int )PyInt_AsLong( PyTuple_GetItem( imageRes, 1 ) );
+
+ options = ( int )PyInt_AsLong( opts );
+ bMakeMask = (options & OPTS_MASK) == OPTS_MASK;
+ bMakeAlpha = (options & OPTS_ALPHA) == OPTS_ALPHA;
+ bInvertMask = (options & OPTS_INVERT_MASK_BITS) == OPTS_INVERT_MASK_BITS;
+
+ // FIXME: error if bMakeMask == bMaskAlpha
+
+ bEnableDstAlpha = bMakeMask || bMakeAlpha;
+
+ GDALAllRegister();
+
+/* -------------------------------------------------------------------- */
+/* Open source dataset. */
+/* -------------------------------------------------------------------- */
+ hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly );
+
+ if( hSrcDS == NULL )
+ {
+ PYTHON_CPL_ERR( PyExc_IOError );
+ LEAVE_NOW( CPLGetLastErrorNo() );
+ }
+
+ if( pszSourceSRS == NULL )
+ {
+ if( GDALGetProjectionRef( hSrcDS ) != NULL
+ && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
+ pszSourceSRS = CPLStrdup(GDALGetProjectionRef( hSrcDS ));
+
+ else if( GDALGetGCPProjection( hSrcDS ) != NULL
+ && strlen(GDALGetGCPProjection(hSrcDS)) > 0
+ && GDALGetGCPCount( hSrcDS ) > 1 )
+ pszSourceSRS = CPLStrdup(GDALGetGCPProjection( hSrcDS ));
+ else
+ pszSourceSRS = CPLStrdup("");
+ }
+
+ if( pszTargetSRS != NULL && strlen(pszSourceSRS) == 0 )
+ {
+ PyErr_Format(PyExc_ValueError,
+ "A target projection was specified, "
+ "but there is no source projection in %s", pszSrcFilename );
+ LEAVE_NOW( 1 );
+ }
+
+ if( pszTargetSRS == NULL )
+ pszTargetSRS = CPLStrdup(pszSourceSRS);
+
+ if( GDALGetRasterColorInterpretation(
+ GDALGetRasterBand(hSrcDS,GDALGetRasterCount(hSrcDS)) )
+ == GCI_AlphaBand
+ && !bEnableSrcAlpha )
+ {
+ bEnableSrcAlpha = TRUE;
+#if 0
+ printf( "Using band %d of source image as alpha.\n",
+ GDALGetRasterCount(hSrcDS) );
+#endif
+ }
+
+
+/* -------------------------------------------------------------------- */
+/* If not, we need to create it. */
+/* -------------------------------------------------------------------- */
+ if( hDstDS == NULL )
+ {
+ hDstDS = GDALWarpCreateOutput( hSrcDS, pszDstFilename, pszFormat,
+ pszSourceSRS, pszTargetSRS, nOrder,
+ papszCreateOptions, eOutputType );
+ bCreateOutput = TRUE;
+
+ papszWarpOptions = CSLSetNameValue(papszWarpOptions, "INIT_DEST", "0");
+
+ CSLDestroy( papszCreateOptions );
+ papszCreateOptions = NULL;
+ }
+
+ if( hDstDS == NULL )
+ {
+ PyErr_Format(PyExc_IOError,
+ "Error creating destination image for projecting %s",
+ pszSrcFilename);
+ LEAVE_NOW( CPLE_FileIO );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Create a transformation object from the source to */
+/* destination coordinate system. */
+/* -------------------------------------------------------------------- */
+ hTransformArg = hGenImgProjArg =
+ GDALCreateGenImgProjTransformer( hSrcDS, pszSourceSRS,
+ hDstDS, pszTargetSRS,
+ TRUE, 1000.0, nOrder );
+
+
+ if( hTransformArg == NULL )
+ {
+ PYTHON_CPL_ERR(PyExc_ValueError );
+ LEAVE_NOW( CPLE_IllegalArg );
+ }
+
+ pfnTransformer = GDALGenImgProjTransform;
+
+ CPLFree( pszSourceSRS );
+ pszSourceSRS = NULL;
+
+ CPLFree( pszTargetSRS );
+ pszTargetSRS = NULL;
+
+/* -------------------------------------------------------------------- */
+/* Warp the transformer with a linear approximator unless the */
+/* acceptable error is zero. */
+/* -------------------------------------------------------------------- */
+ if( dfErrorThreshold != 0.0 )
+ {
+ hTransformArg = hApproxArg =
+ GDALCreateApproxTransformer( GDALGenImgProjTransform,
+ hGenImgProjArg, dfErrorThreshold );
+ pfnTransformer = GDALApproxTransform;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Setup warp options. */
+/* -------------------------------------------------------------------- */
+ psWO = GDALCreateWarpOptions();
+
+ psWO->papszWarpOptions = papszWarpOptions;
+ psWO->eWorkingDataType = eWorkingType;
+ psWO->eResampleAlg = eResampleAlg;
+
+ psWO->hSrcDS = hSrcDS;
+ psWO->hDstDS = hDstDS;
+
+ psWO->pfnTransformer = pfnTransformer;
+ psWO->pTransformerArg = hTransformArg;
+
+ if( dfWarpMemoryLimit != 0.0 )
+ psWO->dfWarpMemoryLimit = dfWarpMemoryLimit;
+
+/* -------------------------------------------------------------------- */
+/* Setup band mapping. */
+/* -------------------------------------------------------------------- */
+ if( bEnableSrcAlpha )
+ psWO->nBandCount = GDALGetRasterCount(hSrcDS) - 1;
+ else
+ psWO->nBandCount = GDALGetRasterCount(hSrcDS);
+
+ psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+ psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+
+ for( i = 0; i < psWO->nBandCount; i++ )
+ {
+ psWO->panSrcBands[i] = i+1;
+ psWO->panDstBands[i] = i+1;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Setup alpha bands used if any. */
+/* -------------------------------------------------------------------- */
+ if( bEnableSrcAlpha )
+ psWO->nSrcAlphaBand = GDALGetRasterCount(hSrcDS);
+
+ if( !bEnableDstAlpha
+ && GDALGetRasterCount(hDstDS) == psWO->nBandCount+1
+ && GDALGetRasterColorInterpretation(
+ GDALGetRasterBand(hDstDS,GDALGetRasterCount(hDstDS)))
+ == GCI_AlphaBand )
+ {
+#if 0
+ printf( "Using band %d of destination image as alpha.\n",
+ GDALGetRasterCount(hDstDS) );
+#endif
+
+ bEnableDstAlpha = TRUE;
+ }
+
+ if( bEnableDstAlpha )
+ psWO->nDstAlphaBand = GDALGetRasterCount(hDstDS);
+
+/* -------------------------------------------------------------------- */
+/* Setup NODATA options. */
+/* -------------------------------------------------------------------- */
+#if 0
+ if( pszSrcNodata != NULL )
+ {
+ char **papszTokens = CSLTokenizeString( pszSrcNodata );
+ int nTokenCount = CSLCount(papszTokens);
+
+ psWO->padfSrcNoDataReal = (double *)
+ CPLMalloc(psWO->nBandCount*sizeof(double));
+ psWO->padfSrcNoDataImag = (double *)
+ CPLMalloc(psWO->nBandCount*sizeof(double));
+
+ for( i = 0; i < psWO->nBandCount; i++ )
+ {
+ if( i < nTokenCount )
+ {
+ CPLStringToComplex( papszTokens[i],
+ psWO->padfSrcNoDataReal + i,
+ psWO->padfSrcNoDataImag + i );
+ }
+ else
+ {
+ psWO->padfSrcNoDataReal[i] = psWO->padfSrcNoDataReal[i-1];
+ psWO->padfSrcNoDataImag[i] = psWO->padfSrcNoDataImag[i-1];
+ }
+ }
+
+ CSLDestroy( papszTokens );
+ }
+
+/* -------------------------------------------------------------------- */
+/* If the output dataset was created, and we have a destination */
+/* nodata value, go through marking the bands with the information.*/
+/* -------------------------------------------------------------------- */
+ if( pszDstNodata != NULL && bCreateOutput )
+ {
+ char **papszTokens = CSLTokenizeString( pszDstNodata );
+ int nTokenCount = CSLCount(papszTokens);
+
+ psWO->padfDstNoDataReal = (double *)
+ CPLMalloc(psWO->nBandCount*sizeof(double));
+ psWO->padfDstNoDataImag = (double *)
+ CPLMalloc(psWO->nBandCount*sizeof(double));
+
+ for( i = 0; i < psWO->nBandCount; i++ )
+ {
+ if( i < nTokenCount )
+ {
+ CPLStringToComplex( papszTokens[i],
+ psWO->padfDstNoDataReal + i,
+ psWO->padfDstNoDataImag + i );
+ }
+ else
+ {
+ psWO->padfDstNoDataReal[i] = psWO->padfDstNoDataReal[i-1];
+ psWO->padfDstNoDataImag[i] = psWO->padfDstNoDataImag[i-1];
+ }
+
+ if( bCreateOutput )
+ {
+ GDALSetRasterNoDataValue(
+ GDALGetRasterBand( hDstDS, psWO->panDstBands[i] ),
+ psWO->padfDstNoDataReal[i] );
+ }
+ }
+
+ CSLDestroy( papszTokens );
+ }
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Initialize and execute the warp. */
+/* -------------------------------------------------------------------- */
+
+ if( oWO.Initialize( psWO ) == CE_None )
+ {
+ if( bMulti )
+ oWO.ChunkAndWarpMulti( 0, 0,
+ GDALGetRasterXSize( hDstDS ),
+ GDALGetRasterYSize( hDstDS ) );
+ else
+ oWO.ChunkAndWarpImage( 0, 0,
+ GDALGetRasterXSize( hDstDS ),
+ GDALGetRasterYSize( hDstDS ) );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Cleanup */
+/* -------------------------------------------------------------------- */
+ if( hApproxArg != NULL )
+ GDALDestroyApproxTransformer( hApproxArg );
+
+ if( hGenImgProjArg != NULL )
+ GDALDestroyGenImgProjTransformer( hGenImgProjArg );
+
+/* -------------------------------------------------------------------- */
+/* Cleanup. */
+/* -------------------------------------------------------------------- */
+ CPLErrorReset();
+ err = 0;
+
+ imglen = 0;
+ imgbuf = NULL;
+ masklen = 0;
+ maskbuf = NULL;
+
+ if ( GetImageData((GDALDataset *)hDstDS,
+ &imgbuf, &imglen, &maskbuf, &masklen) == CE_None)
+ {
+ pyImageData = PyString_FromStringAndSize( ( char * )imgbuf, imglen);
+
+ pyReturnData = PyTuple_New(3);
+ PyTuple_SetItem(pyReturnData, 0, pyImageData);
+
+ if (bMakeAlpha && maskbuf != NULL)
+ {
+ pyMaskData = PyString_FromStringAndSize( ( char * )maskbuf,masklen);
+ PyTuple_SetItem(pyReturnData, 1, Py_None);
+ PyTuple_SetItem(pyReturnData, 2, pyMaskData);
+ }
+ else if (bMakeMask && maskbuf != NULL)
+ {
+ pyMaskData = PyString_FromStringAndSize( ( char * )maskbuf,masklen);
+ PyTuple_SetItem(pyReturnData, 1, pyMaskData);
+ PyTuple_SetItem(pyReturnData, 2, Py_None);
+ }
+ else
+ {
+ PyTuple_SetItem(pyReturnData, 1, Py_None);
+ PyTuple_SetItem(pyReturnData, 2, Py_None);
+ }
+
+ if (imgbuf != NULL) { CPLFree(imgbuf); imgbuf = NULL; }
+ if (maskbuf != NULL) { CPLFree(maskbuf); maskbuf = NULL; }
+
+ }
+
+getOut:
+
+ GDALClose( hDstDS );
+ GDALClose( hSrcDS );
+
+ if (psWO != NULL) GDALDestroyWarpOptions( psWO );
+
+ //GDALDumpOpenDatasets( stderr );
+
+ GDALDestroyDriverManager();
+
+# if PY_VERSION_HEX >=0x02040000
+ if (savedlocale)
+ setlocale( LC_NUMERIC, savedlocale);
+# endif
+
+ if ( !err && CPLGetLastErrorNo() )
+ {
+ PYTHON_CPL_ERR( PyExc_StandardError );
+ return NULL;
+ }
+
+ if ( err )
+ {
+ return NULL;
+ }
+ else
+ {
+ return pyReturnData;
+ }
+}
+
+/************************************************************************/
+/* GDALWarpCreateOutput() */
+/* */
+/* Create the output file based on various commandline options, */
+/* and the input file. */
+/************************************************************************/
+
+static GDALDatasetH
+GDALWarpCreateOutput( GDALDatasetH hSrcDS, const char *pszFilename,
+ const char *pszFormat, const char *pszSourceSRS,
+ const char *pszTargetSRS, int nOrder,
+ char **papszCreateOptions, GDALDataType eDT )
+
+
+{
+ GDALDriverH hDriver;
+ GDALDatasetH hDstDS;
+ void *hTransformArg;
+ double adfDstGeoTransform[6];
+ int nPixels=0, nLines=0;
+
+ CPLErrorReset();
+
+ if( eDT == GDT_Unknown )
+ eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDS,1));
+
+/* -------------------------------------------------------------------- */
+/* Find the output driver. */
+/* -------------------------------------------------------------------- */
+ hDriver = GDALGetDriverByName( pszFormat );
+ if( hDriver == NULL
+ || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL )
+ {
+#if 0
+ int iDr;
+
+ printf( "Output driver `%s' not recognised or does not support\n",
+ pszFormat );
+ printf( "direct output file creation. The following format drivers are configured\n"
+ "and support direct output:\n" );
+
+ for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
+ {
+ GDALDriverH hDriver = GDALGetDriver(iDr);
+
+ if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL) != NULL )
+ {
+ printf( " %s: %s\n",
+ GDALGetDriverShortName( hDriver ),
+ GDALGetDriverLongName( hDriver ) );
+ }
+ }
+ printf( "\n" );
+#endif
+
+ return NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Create a transformation object from the source to */
+/* destination coordinate system. */
+/* -------------------------------------------------------------------- */
+ hTransformArg =
+ GDALCreateGenImgProjTransformer( hSrcDS, pszSourceSRS,
+ NULL, pszTargetSRS,
+ TRUE, 1000.0, nOrder );
+
+ if( hTransformArg == NULL )
+ return NULL;
+
+ //
+ // This could happen if the proj library didn't load correctly
+ // Fixes RF#2947
+ //
+ if (CPLGetLastErrorNo() != CE_None)
+ {
+ GDALDestroyGenImgProjTransformer(hTransformArg);
+ return NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Get approximate output definition. */
+/* -------------------------------------------------------------------- */
+ if( GDALSuggestedWarpOutput( hSrcDS,
+ GDALGenImgProjTransform, hTransformArg,
+ adfDstGeoTransform, &nPixels, &nLines )
+ != CE_None )
+ return NULL;
+
+ GDALDestroyGenImgProjTransformer( hTransformArg );
+
+/* -------------------------------------------------------------------- */
+/* Did the user override some parameters? */
+/* -------------------------------------------------------------------- */
+ if( dfXRes != 0.0 && dfYRes != 0.0 )
+ {
+ CPLAssert( nForcePixels == 0 && nForceLines == 0 );
+ if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+ {
+ dfMinX = adfDstGeoTransform[0];
+ dfMaxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels;
+ dfMaxY = adfDstGeoTransform[3];
+ dfMinY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines;
+ }
+
+ nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
+ nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
+ adfDstGeoTransform[0] = dfMinX;
+ adfDstGeoTransform[3] = dfMaxY;
+ adfDstGeoTransform[1] = dfXRes;
+ adfDstGeoTransform[5] = -dfYRes;
+ }
+
+ else if( nForcePixels != 0 && nForceLines != 0 )
+ {
+ if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+ {
+ dfMinX = adfDstGeoTransform[0];
+ dfMaxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels;
+ dfMaxY = adfDstGeoTransform[3];
+ dfMinY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines;
+ }
+
+ dfXRes = (dfMaxX - dfMinX) / nForcePixels;
+ dfYRes = (dfMaxY - dfMinY) / nForceLines;
+
+ adfDstGeoTransform[0] = dfMinX;
+ adfDstGeoTransform[3] = dfMaxY;
+ adfDstGeoTransform[1] = dfXRes;
+ adfDstGeoTransform[5] = -dfYRes;
+
+ nPixels = nForcePixels;
+ nLines = nForceLines;
+ }
+
+ else if( dfMinX != 0.0 || dfMinY != 0.0 || dfMaxX != 0.0 || dfMaxY != 0.0 )
+ {
+ dfXRes = adfDstGeoTransform[1];
+ dfYRes = fabs(adfDstGeoTransform[5]);
+
+ nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes);
+ nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes);
+
+ adfDstGeoTransform[0] = dfMinX;
+ adfDstGeoTransform[3] = dfMaxY;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Do we want to generate an alpha band in the output file? */
+/* -------------------------------------------------------------------- */
+ int nDstBandCount = GDALGetRasterCount(hSrcDS);
+
+ if( bEnableSrcAlpha )
+ nDstBandCount--;
+
+ if( bEnableDstAlpha )
+ nDstBandCount++;
+
+/* -------------------------------------------------------------------- */
+/* Create the output file. */
+/* -------------------------------------------------------------------- */
+ hDstDS = GDALCreate( hDriver, pszFilename, nPixels, nLines,
+ nDstBandCount, eDT, papszCreateOptions );
+
+ if( hDstDS == NULL )
+ return NULL;
+
+/* -------------------------------------------------------------------- */
+/* Write out the projection definition. */
+/* -------------------------------------------------------------------- */
+ GDALSetProjection( hDstDS, pszTargetSRS );
+ GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
+
+/* -------------------------------------------------------------------- */
+/* Try to set color interpretation of output file alpha band. */
+/* TODO: We should likely try to copy the other bands too. */
+/* -------------------------------------------------------------------- */
+ if( bEnableDstAlpha )
+ {
+ GDALSetRasterColorInterpretation(
+ GDALGetRasterBand( hDstDS, nDstBandCount ),
+ GCI_AlphaBand );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Copy the color table, if required. */
+/* -------------------------------------------------------------------- */
+ GDALColorTableH hCT;
+
+ hCT = GDALGetRasterColorTable( GDALGetRasterBand(hSrcDS,1) );
+ if( hCT != NULL )
+ GDALSetRasterColorTable( GDALGetRasterBand(hDstDS,1), hCT );
+
+ return hDstDS;
+}
+
Added: packages/thuban/branches/upstream/current/libraries/thuban/swigPtrConvertHack.h
===================================================================
--- packages/thuban/branches/upstream/current/libraries/thuban/swigPtrConvertHack.h 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/thuban/swigPtrConvertHack.h 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,123 @@
+#ifndef __WXHACK_H
+#define __WXHACK_H
+
+#include <wx/wx.h>
+
+/* helper function to extract the pointer value from a swig ptr string
+ * as used in wxPython 2.4
+ */
+static void *
+decode_pointer(char *string)
+{
+ unsigned long p = 0;
+
+ /* Pointer values must start with leading underscore */
+ if (*string == '_')
+ {
+ string++;
+ /* Extract hex value from pointer */
+ while (*string)
+ {
+ if ((*string >= '0') && (*string <= '9'))
+ p = (p << 4) + (*string - '0');
+ else if ((*string >= 'a') && (*string <= 'f'))
+ p = (p << 4) + ((*string - 'a') + 10);
+ else
+ break;
+ string++;
+ }
+ }
+ return (void*)p;
+}
+
+/* helper function to extract the pointer value from a swig ptr string
+ * as used in wxPython 2.5
+ *
+ * The hexvalues describe the bytes making up the pointer in memory,
+ * i.e. when the pointer is considered as an array of bytes (we assume
+ * char==byte in the implementation). In the older version it was
+ * always a bigendian representation.
+ */
+static void*
+decode_pointer_new(char *string, unsigned int length)
+{
+ void * p = 0;
+ unsigned char *pp = (unsigned char*)&p;
+ unsigned int count = 0;
+
+ /* sanity check: the string must be at least as long as twice the
+ * size of the pointer (two hex digits per byte) plus one for the
+ * initial underscore */
+ if (length < 2 * sizeof(p) + 1)
+ return NULL;
+
+ /* Pointer values must start with leading underscore */
+ if (*string == '_')
+ {
+ string++;
+ length--;
+
+ /* the remaining length must be at least twice as long as the
+ * size of the pointer. */
+
+ /* now decode the hex values. We decode exactly two bytes for
+ * each of the bytes in the pointer */
+ while (count < 2 * sizeof(p))
+ {
+ if ((*string >= '0') && (*string <= '9'))
+ *pp = (*pp << 4) + (*string - '0');
+ else if ((*string >= 'a') && (*string <= 'f'))
+ *pp = (*pp << 4) + ((*string - 'a') + 10);
+ else
+ break;
+ string++;
+ count++;
+ if (count % 2 == 0)
+ pp++;
+ }
+ }
+ return p;
+}
+
+/* Return the object wrapped by the SWIG shadow object shadow
+ *
+ * The pointer to the real object can be decoded from the "this"
+ * attribute of the python object. In wxPython 2.4 it's a string
+ * containing a hex representation of the pointer value. In wxPython
+ * 2.5 it's a special python object which can nevertheless be converted
+ * to a string with a hex representation of the pointer value which is a
+ * bit different than the one for 2.4.
+ */
+bool
+wxPyConvertSwigPtr(PyObject* obj, void **ptr, const wxChar* className)
+{
+ PyObject * string = NULL;
+ PyObject * thisobject = NULL;
+
+ *ptr = 0;
+
+ thisobject = PyObject_GetAttrString(obj, "this");
+ if (thisobject)
+ {
+ if (!PyString_Check(thisobject))
+ {
+ string = PyObject_Str(thisobject);
+ if (string)
+ {
+ *ptr = decode_pointer_new(PyString_AsString(string),
+ PyString_Size(string));
+ Py_DECREF(string);
+ }
+ }
+ else
+ {
+ *ptr = decode_pointer(PyString_AsString(thisobject));
+ }
+ }
+
+ Py_XDECREF(thisobject);
+
+ return *ptr != 0;
+}
+
+#endif
Added: packages/thuban/branches/upstream/current/libraries/thuban/wxPython_int.h
===================================================================
--- packages/thuban/branches/upstream/current/libraries/thuban/wxPython_int.h 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/thuban/wxPython_int.h 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,302 @@
+////////////////////////////////////////////////////////////////////////////
+// Name: wxPython_int.h (int == internal)
+// Purpose: Helper functions/classes for the wxPython extension module
+// This header should only be inclued directly by those source
+// modules included in the wx._core module. All others should
+// include wx/wxPython/wxPython.h instead.
+//
+// Author: Robin Dunn
+//
+// Created: 1-July-1997
+// RCS-ID: $Id: wxPython_int.h 2562 2005-02-16 21:14:47Z jonathan $
+// Copyright: (c) 1998 by Total Control Software
+// Licence: wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef __wxp_helpers__
+#define __wxp_helpers__
+
+#include <wx/wx.h>
+
+#if 1
+#include <wx/busyinfo.h>
+#include <wx/caret.h>
+//#include <wx/choicebk.h>
+#include <wx/clipbrd.h>
+#include <wx/colordlg.h>
+#include <wx/config.h>
+#include <wx/cshelp.h>
+//#include <wx/dcmirror.h>
+#include <wx/dcps.h>
+#include <wx/dirctrl.h>
+#include <wx/dirdlg.h>
+#include <wx/dnd.h>
+#include <wx/docview.h>
+#include <wx/encconv.h>
+#include <wx/fdrepdlg.h>
+#include <wx/fileconf.h>
+#include <wx/filesys.h>
+#include <wx/fontdlg.h>
+#include <wx/fs_inet.h>
+#include <wx/fs_mem.h>
+#include <wx/fs_zip.h>
+//#include <wx/gbsizer.h>
+#include <wx/geometry.h>
+//#include <wx/htmllbox.h>
+#include <wx/image.h>
+#include <wx/imaglist.h>
+#include <wx/intl.h>
+#include <wx/laywin.h>
+//#include <wx/listbook.h>
+#include <wx/minifram.h>
+#include <wx/notebook.h>
+#include <wx/print.h>
+#include <wx/printdlg.h>
+#include <wx/process.h>
+#include <wx/progdlg.h>
+#include <wx/sashwin.h>
+#include <wx/spinbutt.h>
+#include <wx/spinctrl.h>
+#include <wx/splash.h>
+#include <wx/splitter.h>
+#include <wx/statline.h>
+#include <wx/stream.h>
+#include <wx/sysopt.h>
+#include <wx/taskbar.h>
+#include <wx/tglbtn.h>
+#include <wx/tipwin.h>
+#include <wx/tooltip.h>
+//#include <wx/vlbox.h>
+//#include <wx/vscroll.h>
+#endif
+
+typedef unsigned char byte;
+typedef wxPoint2DDouble wxPoint2D;
+//---------------------------------------------------------------------------
+
+// A macro that will help to execute simple statments wrapped in
+// StartBlock/EndBlockThreads calls
+#define wxPyBLOCK_THREADS(stmt) \
+ { bool blocked = wxPyBeginBlockThreads(); stmt; wxPyEndBlockThreads(blocked); }
+
+// Raise the NotImplementedError exception (blocking threads)
+#define wxPyRaiseNotImplemented() \
+ wxPyBLOCK_THREADS(PyErr_SetNone(PyExc_NotImplementedError))
+
+// Raise any exception witha string value (blocking threads)
+#define wxPyErr_SetString(err, str) \
+ wxPyBLOCK_THREADS(PyErr_SetString(err, str))
+
+
+//---------------------------------------------------------------------------
+
+#if PYTHON_API_VERSION < 1009
+#define PySequence_Fast_GET_ITEM(o, i) \
+ (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i))
+#endif
+
+#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; }
+#define DECLARE_DEF_STRING(name) static const wxString wxPy##name(wx##name)
+#define DECLARE_DEF_STRING2(name,val) static const wxString wxPy##name(val)
+
+//---------------------------------------------------------------------------
+
+#ifndef wxPyUSE_EXPORTED_API
+
+class wxPyCallback : public wxObject {
+ DECLARE_ABSTRACT_CLASS(wxPyCallback);
+public:
+ wxPyCallback(PyObject* func);
+ wxPyCallback(const wxPyCallback& other);
+ ~wxPyCallback();
+
+ void EventThunker(wxEvent& event);
+
+ PyObject* m_func;
+};
+
+#endif // wxPyUSE_EXPORTED_API
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+// These Event classes can be derived from in Python and passed through the
+// event system without loosing anything. They do this by keeping a reference
+// to themselves and some special case handling in wxPyCallback::EventThunker.
+
+
+
+class wxPyEvtSelfRef {
+public:
+ wxPyEvtSelfRef();
+ ~wxPyEvtSelfRef();
+
+ void SetSelf(PyObject* self, bool clone=false);
+ PyObject* GetSelf() const;
+ bool GetCloned() const { return m_cloned; }
+
+protected:
+ PyObject* m_self;
+ bool m_cloned;
+};
+
+
+class wxPyEvent : public wxEvent, public wxPyEvtSelfRef {
+ DECLARE_ABSTRACT_CLASS(wxPyEvent)
+public:
+ wxPyEvent(int winid=0, wxEventType commandType = wxEVT_NULL);
+ wxPyEvent(const wxPyEvent& evt);
+ ~wxPyEvent();
+
+ virtual wxEvent* Clone() const { return new wxPyEvent(*this); }
+};
+
+
+class wxPyCommandEvent : public wxCommandEvent, public wxPyEvtSelfRef {
+ DECLARE_ABSTRACT_CLASS(wxPyCommandEvent)
+public:
+ wxPyCommandEvent(wxEventType commandType = wxEVT_NULL, int id=0);
+ wxPyCommandEvent(const wxPyCommandEvent& evt);
+ ~wxPyCommandEvent();
+
+ virtual wxEvent* Clone() const { return new wxPyCommandEvent(*this); }
+};
+
+
+
+//----------------------------------------------------------------------
+// Forward decalre a few things used in the exported API
+class wxPyClientData;
+class wxPyUserData;
+class wxPyOORClientData;
+class wxPyCBInputStream;
+
+void wxPyClientData_dtor(wxPyClientData* self);
+void wxPyUserData_dtor(wxPyUserData* self);
+void wxPyOORClientData_dtor(wxPyOORClientData* self);
+wxPyCBInputStream* wxPyCBInputStream_create(PyObject *py, bool block);
+
+
+//---------------------------------------------------------------------------
+// Export a C API in a struct. Other modules will be able to load this from
+// the wx.core module and will then have safe access to these functions, even if
+// in another shared library.
+
+class wxPyCallbackHelper;
+struct swig_type_info;
+struct swig_const_info;
+
+typedef double (*py_objasdbl_conv)(PyObject *obj);
+
+// Make SunCC happy and make typedef's for these that are extern "C"
+typedef swig_type_info* (*p_SWIG_Python_TypeRegister_t)(swig_type_info *);
+typedef swig_type_info* (*p_SWIG_Python_TypeCheck_t)(char *c, swig_type_info *);
+typedef void* (*p_SWIG_Python_TypeCast_t)(swig_type_info *, void *);
+typedef swig_type_info* (*p_SWIG_Python_TypeDynamicCast_t)(swig_type_info *, void **);
+typedef const char* (*p_SWIG_Python_TypeName_t)(const swig_type_info *);
+typedef const char * (*p_SWIG_Python_TypePrettyName_t)(const swig_type_info *);
+typedef swig_type_info* (*p_SWIG_Python_TypeQuery_t)(const char *);
+typedef void (*p_SWIG_Python_TypeClientData_t)(swig_type_info *, void *);
+typedef PyObject* (*p_SWIG_Python_newvarlink_t)(void);
+typedef void (*p_SWIG_Python_addvarlink_t)(PyObject *, char *, PyObject *(*)(void), int (*)(PyObject *));
+typedef int (*p_SWIG_Python_ConvertPtr_t)(PyObject *, void **, swig_type_info *, int);
+typedef int (*p_SWIG_Python_ConvertPacked_t)(PyObject *, void *, int sz, swig_type_info *, int);
+typedef char* (*p_SWIG_Python_PackData_t)(char *c, void *, int);
+typedef char* (*p_SWIG_Python_UnpackData_t)(char *c, void *, int);
+typedef PyObject* (*p_SWIG_Python_NewPointerObj_t)(void *, swig_type_info *,int own);
+typedef PyObject* (*p_SWIG_Python_NewPackedObj_t)(void *, int sz, swig_type_info *);
+typedef void (*p_SWIG_Python_InstallConstants_t)(PyObject *d, swig_const_info constants[]);
+typedef void* (*p_SWIG_Python_MustGetPtr_t)(PyObject *, swig_type_info *, int, int);
+
+
+struct wxPyCoreAPI {
+
+ p_SWIG_Python_TypeRegister_t p_SWIG_Python_TypeRegister;
+ p_SWIG_Python_TypeCheck_t p_SWIG_Python_TypeCheck;
+ p_SWIG_Python_TypeCast_t p_SWIG_Python_TypeCast;
+ p_SWIG_Python_TypeDynamicCast_t p_SWIG_Python_TypeDynamicCast;
+ p_SWIG_Python_TypeName_t p_SWIG_Python_TypeName;
+ p_SWIG_Python_TypePrettyName_t p_SWIG_Python_TypePrettyName;
+ p_SWIG_Python_TypeQuery_t p_SWIG_Python_TypeQuery;
+ p_SWIG_Python_TypeClientData_t p_SWIG_Python_TypeClientData;
+ p_SWIG_Python_newvarlink_t p_SWIG_Python_newvarlink;
+ p_SWIG_Python_addvarlink_t p_SWIG_Python_addvarlink;
+ p_SWIG_Python_ConvertPtr_t p_SWIG_Python_ConvertPtr;
+ p_SWIG_Python_ConvertPacked_t p_SWIG_Python_ConvertPacked;
+ p_SWIG_Python_PackData_t p_SWIG_Python_PackData;
+ p_SWIG_Python_UnpackData_t p_SWIG_Python_UnpackData;
+ p_SWIG_Python_NewPointerObj_t p_SWIG_Python_NewPointerObj;
+ p_SWIG_Python_NewPackedObj_t p_SWIG_Python_NewPackedObj;
+ p_SWIG_Python_InstallConstants_t p_SWIG_Python_InstallConstants;
+ p_SWIG_Python_MustGetPtr_t p_SWIG_Python_MustGetPtr;
+
+ bool (*p_wxPyCheckSwigType)(const wxChar* className);
+ PyObject* (*p_wxPyConstructObject)(void* ptr, const wxChar* className, int setThisOwn);
+ bool (*p_wxPyConvertSwigPtr)(PyObject* obj, void **ptr, const wxChar* className);
+ PyObject* (*p_wxPyMakeSwigPtr)(void* ptr, const wxChar* className);
+
+ PyThreadState* (*p_wxPyBeginAllowThreads)();
+ void (*p_wxPyEndAllowThreads)(PyThreadState* state);
+ bool (*p_wxPyBeginBlockThreads)();
+ void (*p_wxPyEndBlockThreads)(bool blocked);
+
+ PyObject* (*p_wxPy_ConvertList)(wxListBase* list);
+
+ wxString* (*p_wxString_in_helper)(PyObject* source);
+ wxString (*p_Py2wxString)(PyObject* source);
+ PyObject* (*p_wx2PyString)(const wxString& src);
+
+ byte* (*p_byte_LIST_helper)(PyObject* source);
+ int* (*p_int_LIST_helper)(PyObject* source);
+ long* (*p_long_LIST_helper)(PyObject* source);
+ char** (*p_string_LIST_helper)(PyObject* source);
+ wxPoint* (*p_wxPoint_LIST_helper)(PyObject* source, int* npoints);
+ wxBitmap** (*p_wxBitmap_LIST_helper)(PyObject* source);
+ wxString* (*p_wxString_LIST_helper)(PyObject* source);
+ wxAcceleratorEntry* (*p_wxAcceleratorEntry_LIST_helper)(PyObject* source);
+
+ bool (*p_wxSize_helper)(PyObject* source, wxSize** obj);
+ bool (*p_wxPoint_helper)(PyObject* source, wxPoint** obj);
+ bool (*p_wxRealPoint_helper)(PyObject* source, wxRealPoint** obj);
+ bool (*p_wxRect_helper)(PyObject* source, wxRect** obj);
+ bool (*p_wxColour_helper)(PyObject* source, wxColour** obj);
+ bool (*p_wxPoint2D_helper)(PyObject* source, wxPoint2DDouble** obj);
+
+
+ bool (*p_wxPySimple_typecheck)(PyObject* source, const wxChar* classname, int seqLen);
+ bool (*p_wxColour_typecheck)(PyObject* source);
+
+ void (*p_wxPyCBH_setCallbackInfo)(wxPyCallbackHelper& cbh, PyObject* self, PyObject* klass, int incref);
+ bool (*p_wxPyCBH_findCallback)(const wxPyCallbackHelper& cbh, const char* name);
+ int (*p_wxPyCBH_callCallback)(const wxPyCallbackHelper& cbh, PyObject* argTuple);
+ PyObject* (*p_wxPyCBH_callCallbackObj)(const wxPyCallbackHelper& cbh, PyObject* argTuple);
+ void (*p_wxPyCBH_delete)(wxPyCallbackHelper* cbh);
+
+ PyObject* (*p_wxPyMake_wxObject)(wxObject* source, bool setThisOwn, bool checkEvtHandler);
+ PyObject* (*p_wxPyMake_wxSizer)(wxSizer* source, bool setThisOwn);
+ void (*p_wxPyPtrTypeMap_Add)(const char* commonName, const char* ptrName);
+ bool (*p_wxPy2int_seq_helper)(PyObject* source, int* i1, int* i2);
+ bool (*p_wxPy4int_seq_helper)(PyObject* source, int* i1, int* i2, int* i3, int* i4);
+ PyObject* (*p_wxArrayString2PyList_helper)(const wxArrayString& arr);
+ PyObject* (*p_wxArrayInt2PyList_helper)(const wxArrayInt& arr);
+
+ void (*p_wxPyClientData_dtor)(wxPyClientData*);
+ void (*p_wxPyUserData_dtor)(wxPyUserData*);
+ void (*p_wxPyOORClientData_dtor)(wxPyOORClientData*);
+
+ wxPyCBInputStream* (*p_wxPyCBInputStream_create)(PyObject *py, bool block);
+
+ bool (*p_wxPyInstance_Check)(PyObject* obj);
+ bool (*p_wxPySwigInstance_Check)(PyObject* obj);
+
+ bool (*p_wxPyCheckForApp)();
+
+};
+
+
+#ifdef wxPyUSE_EXPORTED_API
+// Notice that this is static, not extern. This is by design, each module
+// needs one, but doesn't have to use it.
+static wxPyCoreAPI* wxPyCoreAPIPtr = NULL;
+inline wxPyCoreAPI* wxPyGetCoreAPIPtr();
+#endif // wxPyUSE_EXPORTED_API
+
+#endif
Added: packages/thuban/branches/upstream/current/libraries/thuban/wxproj.cpp
===================================================================
--- packages/thuban/branches/upstream/current/libraries/thuban/wxproj.cpp 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/libraries/thuban/wxproj.cpp 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,772 @@
+/* Copyright (c) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+ * Authors:
+ * Bernhard Herzog <bh at intevation.de>
+ *
+ * This program is free software under the GPL (>=v2)
+ * Read the file COPYING coming with Thuban for details.
+ */
+
+/* module to read a shape from a shapefile with shapelib, project the
+ * data with proj4 and draw it on a wxWindows DC
+ */
+
+#include <Python.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <shapefil.h>
+#include "pyshapelib_api.h"
+
+#include <proj_api.h>
+
+#include <wx/wx.h>
+
+
+/* By default we use the wxPython.h API to access wxPython's objects at
+ * the C++ level. On some systems that's not available, so we offer a
+ * work-around with swigPtrConvertHack.h, but we only do so if the
+ * compiler explicitly defines USE_WX_PYTHON_SWIG_HACK.
+ */
+#ifndef USE_WX_PYTHON_SWIG_HACK
+#include <wx/wxPython/wxPython.h>
+
+/* Compatibility code to cope with wxPython.h from wxPython 2.4.
+ *
+ * Instead of wxPyConvertSwigPtr there's SWIG_GetPtrObj which has almost
+ * the same interface but is a little different. So we define our own
+ * wxPyConvertSwigPtr if we're being compiled with wxPython 2.4. We
+ * determine that by checking whether a macro wxPyConvertSwigPtr is
+ * defined.
+ *
+ * In wxPython 2.5 the last parameter, type, is of type wxChar* which
+ * may be a wchar_t* and thus incompatible with char* and it's value is
+ * slightly different (the one in 2.4 needs a few more characters
+ * appended and prefixed). Fortunately, it's is always passed via wxT,
+ * a macro that we only use for the type parameter. So redefine it to
+ * do nothing but add the pre- and suffixes necessary for 2.4.
+ */
+#ifndef wxPyConvertSwigPtr
+bool
+wxPyConvertSwigPtr(PyObject *obj, void **ptr, char *type)
+{
+ /* import the API ptr if it hasn't been imported yet */
+ if (wxPyCoreAPIPtr == NULL)
+ wxPyCoreAPI_IMPORT();
+
+ return SWIG_GetPtrObj(obj, ptr, type) == 0;
+}
+#undef wxT
+#define wxT(a) ("_" a "_p")
+#endif /* not wxPyConvertSwigPtr */
+
+#else /* USE_WX_PYTHON_SWIG_HACK */
+#include "swigPtrConvertHack.h"
+#endif /* USE_WX_PYTHON_SWIG_HACK */
+
+/* pyshapelib api pointer */
+static PyShapeLibAPI * pyshapelib_api;
+
+
+/* Extract a pointer from a python object that has a cobject method.
+ *
+ * Call the object's cobject method and if it returns a Py_CObject
+ * extract the pointer from it and write the it into *output and return
+ * true. If unsuccessful set a Python exception, do not modify *output
+ * and return false.
+ *
+ * If object is None, set *output will to NULL.
+ */
+template<class T>
+int
+extract_pointer(PyObject * object, T**output)
+{
+ void * value = NULL;
+ PyObject *cobject = NULL;
+
+ if (Py_None == object)
+ {
+ value = NULL;
+ }
+ else
+ {
+ cobject = PyObject_CallMethod(object, "cobject", NULL);
+ if (!cobject)
+ return 0;
+
+ /* now cobject should be a CObject containing the projPJ* pointer */
+ if (PyCObject_Check(cobject))
+ {
+ value = PyCObject_AsVoidPtr(cobject);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "The projection must be either None, "
+ "or an object whose cobject method "
+ "returns a CObjecta cobject");
+ Py_XDECREF(cobject);
+ return 0;
+ }
+ }
+
+ *output = (T*)value;
+ return 1;
+}
+
+
+/* Project the point (x, y) with the projections forward and inverse and
+ * scale it with scalex, scaley and offset it by offx, offy and store in
+ * *xdest, and *ydest.
+ */
+static void
+project_point(double * xdest, double *ydest,
+ projPJ* forward, projPJ* inverse,
+ double scalex, double scaley, double offx, double offy,
+ double x, double y)
+{
+ projUV proj_point;
+
+ proj_point.u = x;
+ proj_point.v = y;
+
+ if (inverse)
+ proj_point = pj_inv(proj_point, inverse);
+
+ if (forward)
+ {
+ if (!inverse)
+ {
+ /* If a map projection is used but no layer projection we
+ * have to assume that the shapefille data is in geographic
+ * coordinates. Thuban assumes that they're in degrees but
+ * proj uses radians, so we have to convert explicitly. With
+ * a layer projection, i.e. inverse, present we already have
+ * the coordinates in radians.
+ */
+ proj_point.u *= DEG_TO_RAD;
+ proj_point.v *= DEG_TO_RAD;
+ }
+ proj_point = pj_fwd(proj_point, forward);
+ }
+ else if (inverse)
+ {
+ /* if there's an inverse projection but no forward projection
+ * the coordinates are now in radians, so we have to convert
+ * them to degrees.
+ */
+ proj_point.u *= RAD_TO_DEG;
+ proj_point.v *= RAD_TO_DEG;
+ }
+
+
+ *xdest = (scalex * proj_point.u + offx);
+ *ydest = (scaley * proj_point.v + offy);
+}
+
+
+/* Return the projected points as a wxPoint array. The array returned
+ * has a length of num_vertices + num_parts - 1
+ *
+ * The return value is suitable as a parameter to DrawPolygon with a
+ * non-null brush so that the shape will be filled correctly, even
+ * shapes with holes or otherwise consisting of multiple parts. This is
+ * achieved by connecting the start/end points of the parts with lines
+ * in such a way that these lines are given twice, but in opposite
+ * directions. This trick works on both X11 and Windows 2000 (perhaps
+ * on other windows versions too). This trick is the reason why the
+ * returned array has num_vertices + num_parts - 1 items.
+ */
+static wxPoint *
+project_points(int num_vertices, int num_parts,
+ double * xs, double * ys, int * part_start,
+ projPJ* forward, projPJ* inverse,
+ double scalex, double scaley, double offx, double offy)
+{
+ int i;
+ int num_points = num_vertices + num_parts - 1;
+ wxPoint* points = (wxPoint*)malloc(num_points * sizeof(wxPoint));
+ if (!points)
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ for (i = 0; i < num_vertices; i++)
+ {
+ double x, y;
+
+ project_point(&x, &y, forward, inverse,
+ scalex, scaley, offx, offy,
+ xs[i], ys[i]);
+ points[i].x = (int)x;
+ points[i].y = (int)y;
+ }
+
+ /* link all the parts so that we can draw a multipart polygon with
+ * one DrawPolgon call. If the points array as a whole is used for
+ * DrawPolgon, the connections between the start points of the
+ * subparts are already in the polygon, but only in one direction.
+ * Here we add the same connections, but in the opposite order and
+ * direction.
+ */
+ for (i = num_parts - 1; i > 0; i--)
+ {
+ points[num_vertices + num_parts - 1 - i] = points[part_start[i]];
+ }
+
+ return points;
+}
+
+/*
+ * Structure to hold common data for calls to draw_polygon_shape().
+ */
+struct s_draw_info
+{
+ PyObject * py_shapefile;
+ PyObject * py_forward;
+ PyObject * py_inverse;
+ PyObject * py_dc;
+ double scalex, scaley, offx, offy;
+ SHPHandle handle;
+ projPJ * forward;
+ projPJ * inverse;
+ wxDC * dc;
+};
+
+
+/* Free a draw info struct */
+static void
+free_draw_info(void * p_draw_info)
+{
+ s_draw_info * draw_info = (s_draw_info*)p_draw_info;
+ Py_XDECREF(draw_info->py_shapefile);
+ Py_XDECREF(draw_info->py_dc);
+ Py_XDECREF(draw_info->py_forward);
+ Py_XDECREF(draw_info->py_inverse);
+ delete draw_info;
+}
+
+
+/*
+ * Initialize the structure for drawing polygons. Call once for each
+ * layer and pass the return value to draw_polygon_shape.
+ */
+static PyObject *
+draw_polygon_init(PyObject *, PyObject * args)
+{
+ PyObject * py_shapefile;
+ PyObject * py_forward;
+ PyObject * py_inverse;
+ PyObject * py_dc;
+ double scalex, scaley, offx, offy;
+
+ if (!PyArg_ParseTuple(args, "OOOOdddd",
+ &py_shapefile,
+ &py_dc, &py_forward, &py_inverse,
+ &scalex, &scaley, &offx, &offy))
+ return NULL;
+
+ s_draw_info * draw_info = new s_draw_info;
+
+ draw_info->py_shapefile = 0;
+ draw_info->py_dc = 0;
+ draw_info->py_forward = 0;
+ draw_info->py_inverse = 0;
+
+ draw_info->py_shapefile = py_shapefile;
+ Py_INCREF(draw_info->py_shapefile);
+ if (!extract_pointer(draw_info->py_shapefile, &draw_info->handle))
+ goto fail;
+
+ draw_info->py_dc = py_dc;
+ Py_INCREF(draw_info->py_dc);
+ if (!wxPyConvertSwigPtr( py_dc, (void**)&(draw_info->dc), wxT("wxDC") ))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "third argument must be a wxDC instance");
+ goto fail;
+ }
+
+ draw_info->py_forward = py_forward;
+ Py_INCREF(draw_info->py_forward);
+ if (!extract_pointer(draw_info->py_forward, &draw_info->forward))
+ goto fail;
+
+ draw_info->py_inverse = py_inverse;
+ Py_INCREF(draw_info->py_inverse);
+ if (!extract_pointer(draw_info->py_inverse, &draw_info->inverse))
+ goto fail;
+
+ draw_info->scalex = scalex;
+ draw_info->scaley = scaley;
+ draw_info->offx = offx;
+ draw_info->offy = offy;
+
+ return PyCObject_FromVoidPtr(draw_info, free_draw_info);
+
+ fail:
+ free_draw_info(draw_info);
+ return NULL;
+}
+
+
+/*
+ * Draw a polygon. draw_polygon_init() MUST be called prior to this function.
+ */
+static PyObject *
+draw_polygon_shape(PyObject *, PyObject * args)
+{
+ int shape_index = 0;
+ PyObject * brush_shadow;
+ PyObject * pen_shadow;
+ SHPObject * shape;
+ wxPoint* points;
+ wxPen * pen;
+ wxBrush * brush;
+ int num_points;
+ wxDC * dc;
+ PyObject * py_draw_info;
+ s_draw_info * draw_info;
+
+ if (!PyArg_ParseTuple(args, "O!iOO",
+ &PyCObject_Type, &py_draw_info,
+ &shape_index, &pen_shadow, &brush_shadow))
+ return NULL;
+
+ draw_info = (s_draw_info*)PyCObject_AsVoidPtr(py_draw_info);
+
+ if (pen_shadow == Py_None)
+ {
+ pen = NULL;
+ }
+ else
+ {
+ if (!wxPyConvertSwigPtr( pen_shadow, (void**)&pen, wxT("wxPen")))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "fourth argument must be a wxPen instance or None");
+ return NULL;
+ }
+ }
+
+ if (brush_shadow == Py_None)
+ {
+ brush = NULL;
+ }
+ else
+ {
+ if (!wxPyConvertSwigPtr( brush_shadow, (void**)&brush, wxT("wxBrush")))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "fifth argument must be a wxBrush instance or None");
+ return NULL;
+ }
+ }
+
+ shape = pyshapelib_api->SHPReadObject(draw_info->handle, shape_index);
+ if (!shape)
+ return PyErr_Format(PyExc_ValueError,
+ "Can't get shape %d from shapefile", shape_index);
+
+ num_points = shape->nVertices + shape->nParts - 1;
+ points = project_points(shape->nVertices, shape->nParts,
+ shape->padfX, shape->padfY, shape->panPartStart,
+ draw_info->forward,
+ draw_info->inverse,
+ draw_info->scalex,
+ draw_info->scaley,
+ draw_info->offx,
+ draw_info->offy);
+ dc = draw_info->dc;
+
+ // If the shape is a polygon and a non-transparent brush was given,
+ // fill the polygon
+ if (shape->nSHPType == SHPT_POLYGON
+ && brush && brush != wxTRANSPARENT_BRUSH)
+ {
+ dc->SetPen(*wxTRANSPARENT_PEN);
+ dc->SetBrush(*brush);
+ dc->DrawPolygon(num_points, points, 0, 0);
+ }
+
+ // If a non-transparent pen was given, stroke the outline
+ if (pen && pen != wxTRANSPARENT_PEN)
+ {
+ draw_info->dc->SetPen(*pen);
+ draw_info->dc->SetBrush(*wxTRANSPARENT_BRUSH);
+ for (int i = 0; i < shape->nParts; i++)
+ {
+ int length;
+
+ if (i < shape->nParts - 1)
+ length = shape->panPartStart[i + 1] - shape->panPartStart[i];
+ else
+ length = shape->nVertices - shape->panPartStart[i];
+
+ // If the shape is a polygon, use DrawPolygon else use DrawLines
+ if (shape->nSHPType == SHPT_POLYGON)
+ {
+ dc->DrawPolygon(length, points + shape->panPartStart[i], 0, 0);
+ }
+ else
+ {
+ dc->DrawLines(length, points + shape->panPartStart[i], 0, 0);
+ }
+ }
+ }
+
+ free(points);
+
+ pyshapelib_api->SHPDestroyObject(shape);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
+/* determine whether the line fom (SX, SY) to (EX, EY) is `hit' by a
+ * click at (PX, PY), or whether a polygon containing this line is hit
+ * in the interior at (PX, PY).
+ *
+ * Return -1 if the line it self his hit. Otherwise, return +1 if a
+ * horizontal line from (PX, PY) to (-Infinity, PY) intersects the line
+ * and 0 if it doesn't.
+ *
+ * The nonnegative return values can be used to determine whether (PX, PY)
+ * is an interior point of a polygon according to the even-odd rule.
+ */
+
+#define PREC_BITS 4
+
+static int
+test_line(int sx, int sy, int ex, int ey, int px, int py)
+{
+ long vx, vy, dx, dy, len, dist, not_horizontal;
+
+ if (ey < sy)
+ {
+ dist = ex; ex = sx; sx = dist;
+ dist = ey; ey = sy; sy = dist;
+ }
+ not_horizontal = ey > sy + (2 << PREC_BITS);
+ if (not_horizontal && (py >= ey || py < sy))
+ return 0;
+
+ vx = ex - sx; vy = ey - sy;
+
+ len = (long)sqrt( (double) vx * vx + vy * vy);
+ if (!len)
+ /* degenerate case of coincident end points. Assumes that some
+ * other part of the code has already determined whether the end
+ * point is hit.
+ */
+ return 0;
+
+ dx = px - sx; dy = py - sy;
+ dist = vx * dy - vy * dx;
+ if ((not_horizontal || (px >= sx && px <= ex) || (px >= ex && px <= sx))
+ && abs(dist) <= (len << (PREC_BITS + 1)))
+ return -1;
+
+ /* horizontal lines (vy == 0) always return 0 here. */
+ return vy && py < ey && py >= sy && dx * abs(vy) > vx * abs(dy);
+}
+
+
+
+static PyObject *
+point_in_polygon_shape(PyObject *, PyObject * args)
+{
+ int shape_index = 0;
+ PyObject * shphandle_cobject;
+ PyObject * forward_cobject;
+ PyObject * inverse_cobject;
+ int filled, stroked;
+ double scalex, scaley, offx, offy;
+ int px, py;
+ SHPHandle handle;
+ projPJ * forward = NULL;
+ projPJ * inverse = NULL;
+ SHPObject * shape;
+ wxPoint* points;
+ int num_points;
+ int cross_count, linehit;
+ int result;
+
+ if (!PyArg_ParseTuple(args, "O!iiiOOddddii",
+ &PyCObject_Type, &shphandle_cobject,
+ &shape_index, &filled, &stroked,
+ &forward_cobject, &inverse_cobject,
+ &scalex, &scaley, &offx, &offy, &px, &py))
+ return NULL;
+
+ handle = (SHPHandle)PyCObject_AsVoidPtr(shphandle_cobject);
+
+ if (!extract_pointer(forward_cobject, &forward))
+ return NULL;
+
+ if (!extract_pointer(inverse_cobject, &inverse))
+ return NULL;
+
+ shape = pyshapelib_api->SHPReadObject(handle, shape_index);
+ if (!shape)
+ return PyErr_Format(PyExc_ValueError,
+ "Can't get shape %d from shapefile", shape_index);
+
+ num_points = shape->nVertices + shape->nParts - 1;
+ points = project_points(shape->nVertices, shape->nParts,
+ shape->padfX, shape->padfY, shape->panPartStart,
+ forward, inverse, scalex, scaley, offx, offy);
+
+ long scaled_px = (px << PREC_BITS) + 1, scaled_py = (py << PREC_BITS) + 1;
+
+ cross_count = 0; linehit = 0;
+ for (int part = 0; part < shape->nParts; part++)
+ {
+ int start, end;
+
+ if (part < shape->nParts - 1)
+ {
+ start = shape->panPartStart[part];
+ end = shape->panPartStart[part + 1] - 1;
+ }
+ else
+ {
+ start = shape->panPartStart[part];
+ end = shape->nVertices - 1;
+ }
+
+ for (int vertex = start; vertex < end; vertex++)
+ {
+ //printf("test_line: %d, %d: %d, %d -- %d, %d",
+ // px, py, points[vertex].x, points[vertex].y,
+ // points[vertex + 1].x, points[vertex + 1].y);
+ result = test_line(points[vertex].x << PREC_BITS,
+ points[vertex].y << PREC_BITS,
+ points[vertex + 1].x << PREC_BITS,
+ points[vertex + 1].y << PREC_BITS,
+ scaled_px, scaled_py);
+ //printf(":\t%d\n", result);
+ if (result < 0)
+ {
+ linehit = 1;
+ break;
+ }
+ cross_count += result;
+ }
+ if (linehit)
+ break;
+ }
+
+ free(points);
+
+ pyshapelib_api->SHPDestroyObject(shape);
+
+ if (filled)
+ {
+ if (stroked && linehit)
+ result = -1;
+ else
+ result = cross_count % 2;
+ }
+ else if (stroked)
+ {
+ if (linehit)
+ result = -1;
+ else
+ result = 0;
+ }
+ else
+ result = 0;
+
+
+ return PyInt_FromLong(result);
+}
+
+
+static PyObject*
+shape_centroid(PyObject *self, PyObject *args)
+{
+ int shape_index = 0;
+ PyObject * shphandle_cobject;
+ PyObject * forward_cobject;
+ PyObject * inverse_cobject;
+ double scalex, scaley, offx, offy;
+ SHPHandle handle;
+ projPJ * forward = NULL;
+ projPJ * inverse = NULL;
+ SHPObject * shape;
+ double centroidx = 0, centroidy = 0;
+ double sum = 0, area;
+ double lastx=0, lasty=0, x, y;
+
+ if (!PyArg_ParseTuple(args, "O!iOOdddd",
+ &PyCObject_Type, &shphandle_cobject,
+ &shape_index, &forward_cobject, &inverse_cobject,
+ &scalex, &scaley, &offx, &offy))
+ return NULL;
+
+ handle = (SHPHandle)PyCObject_AsVoidPtr(shphandle_cobject);
+
+ if (!extract_pointer(forward_cobject, &forward))
+ return NULL;
+
+ if (!extract_pointer(inverse_cobject, &inverse))
+ return NULL;
+
+ shape = pyshapelib_api->SHPReadObject(handle, shape_index);
+ if (!shape)
+ return PyErr_Format(PyExc_ValueError,
+ "Can't get shape %d from shapefile", shape_index);
+
+ for (int part = 0; part < shape->nParts; part++)
+ {
+ int start, end;
+
+ if (part < shape->nParts - 1)
+ {
+ start = shape->panPartStart[part];
+ end = shape->panPartStart[part + 1];
+ }
+ else
+ {
+ start = shape->panPartStart[part];
+ end = shape->nVertices;
+ }
+
+ project_point(&lastx, &lasty, forward, inverse,
+ scalex, scaley, offx, offy,
+ shape->padfX[start],
+ shape->padfY[start]);
+ for (int vertex = start + 1; vertex < end; vertex++)
+ {
+ project_point(&x, &y, forward, inverse,
+ scalex, scaley, offx, offy,
+ shape->padfX[vertex],
+ shape->padfY[vertex]);
+ area = x * lasty - lastx * y;
+ centroidx += area * (x + lastx);
+ centroidy += area * (y + lasty);
+ sum += area;
+ lastx = x;
+ lasty = y;
+ }
+ }
+
+ pyshapelib_api->SHPDestroyObject(shape);
+
+ // Handle pathologic case where all points are equal.
+ if (sum == 0.0)
+ return Py_BuildValue("dd", lastx, lasty);
+ else
+ return Py_BuildValue("dd", centroidx / (3 * sum), centroidy / (3 * sum));
+}
+
+
+/*
+ * Returns a tuple containing the version of PROJ that was used when
+ * compiling this file (major, minor, release). If the version was
+ * not available (because of a very old version of PROJ) the tuple
+ * will be empty.
+ */
+
+static PyObject*
+get_proj_version(PyObject *, PyObject * args)
+{
+ PyObject * result;
+
+#ifdef PJ_VERSION
+ result = PyTuple_New(3);
+ if (result == NULL)
+ return NULL;
+
+ int ver = PJ_VERSION;
+ int major = ver / 100; ver -= major * 100;
+ int minor = ver / 10; ver -= minor * 10;
+ int release = ver;
+
+ PyTuple_SET_ITEM(result, 0, PyInt_FromLong(major));
+ PyTuple_SET_ITEM(result, 1, PyInt_FromLong(minor));
+ PyTuple_SET_ITEM(result, 2, PyInt_FromLong(release));
+#else
+ result = PyTuple_New(0);
+ if (result == NULL)
+ return NULL;
+#endif
+
+ Py_INCREF(result);
+ return result;
+}
+
+
+static PyObject*
+get_gtk_version(PyObject *, PyObject * args)
+{
+ PyObject * result;
+
+#ifdef __WXGTK__
+ extern const int gtk_major_version;
+ extern const int gtk_minor_version;
+ extern const int gtk_micro_version;
+
+ result = PyTuple_New(3);
+ if (result == NULL)
+ return NULL;
+
+ PyTuple_SET_ITEM(result, 0, PyInt_FromLong(gtk_major_version));
+ PyTuple_SET_ITEM(result, 1, PyInt_FromLong(gtk_minor_version));
+ PyTuple_SET_ITEM(result, 2, PyInt_FromLong(gtk_micro_version));
+#else
+ result = PyTuple_New(0);
+ if (result == NULL)
+ return NULL;
+#endif
+
+ Py_INCREF(result);
+ return result;
+}
+
+
+/* Return the version of wxWindows this module was compiled with */
+static PyObject*
+get_wx_version(PyObject *, PyObject * args)
+{
+ return Py_BuildValue("iii", wxMAJOR_VERSION, wxMINOR_VERSION,
+ wxRELEASE_NUMBER);
+}
+
+
+static PyMethodDef wxproj_methods[] = {
+ { "draw_polygon_shape", draw_polygon_shape, METH_VARARGS },
+ { "draw_polygon_init", draw_polygon_init, METH_VARARGS },
+ { "point_in_polygon_shape", point_in_polygon_shape, METH_VARARGS },
+ { "shape_centroid", shape_centroid, METH_VARARGS },
+ { "get_proj_version", get_proj_version, METH_VARARGS },
+ { "get_gtk_version", get_gtk_version, METH_VARARGS },
+ { "get_wx_version", get_wx_version, METH_VARARGS },
+ {NULL, NULL}
+};
+
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void initwxproj(void)
+{
+ PyObject * shapelib = NULL;
+ PyObject * c_api_func = NULL;
+ PyObject * cobj = NULL;
+
+ Py_InitModule("wxproj", wxproj_methods);
+
+ PYSHAPELIB_IMPORT_API(pyshapelib_api);
+
+ Py_XDECREF(cobj);
+ Py_XDECREF(c_api_func);
+ Py_XDECREF(shapelib);
+}
+
+
+
Added: packages/thuban/branches/upstream/current/po/Makefile
===================================================================
--- packages/thuban/branches/upstream/current/po/Makefile 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/Makefile 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,39 @@
+
+all:
+ @echo 'Usage:'
+ @echo ' make pot create thuban.pot'
+ @echo ' make update-po merge a new thuban.po with the *.po files'
+ @echo ' make mo create the mo files'
+
+MO_DIR = ../Resources/Locale
+PO_DIR = po
+DOMAIN = thuban
+
+LIST_POTFILES = grep -l "_(\"" ../Thuban/*.py ../Thuban/*/*.py
+
+
+pot:
+ xgettext -k_ -o $(DOMAIN).pot `$(LIST_POTFILES)`
+
+update-po:
+ for po in *.po; do \
+ lingua=`basename $$po .po`; \
+ mv $$lingua.po $$lingua.old.po; \
+ if msgmerge -o $$lingua.po $$lingua.old.po $(DOMAIN).pot; then\
+ rm $$lingua.old.po; \
+ else \
+ rm -f $$lingua.po; \
+ mv $$lingua.old.po $$lingua.po; \
+ fi \
+ done
+
+
+mo:
+ for po in *.po; do\
+ lingua=`basename $$po .po`; \
+ install -d $(MO_DIR)/$$lingua/LC_MESSAGES/ ; \
+ echo -n $$po": "; \
+ msgfmt --statistics \
+ -o $(MO_DIR)/$$lingua/LC_MESSAGES/$(DOMAIN).mo $$po ;\
+ done
+
Added: packages/thuban/branches/upstream/current/po/README
===================================================================
--- packages/thuban/branches/upstream/current/po/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,35 @@
+
+Thuban Message Translations
+===========================
+
+Updating the message catalogs currently only works on unix-like systems
+and requires xgettext 0.11. (0.10.x may work for everything but it will
+at least produce a lot of warnings during "make pot" because it doesn't
+know about python syntax.)
+
+ - When the thuban sources were edited so that e.g. messages have been
+ changed or added, run
+
+ $ make pot
+
+ to update the thuban.pot file. You also need to do this after a fresh
+ CVS checkout to build thuban.pot
+
+ - When the thuban.pot file has been changed, run
+
+ $ make update-po
+
+ to merge the changes in the pot file with the messages already in the
+ .po files.
+
+ - When the translations in the po files have been changed, run
+
+ $ make mo
+
+ to generate new .mo files under ../Thuban/Resources/Locale
+
+ - The make mo command prints statistics about the translations. To get
+ a less verbose version use this:
+
+ $ make mo 2>&1 | sed -e 's/ \(messages\|translations\)//g' -e 's/\.$//'
+
Added: packages/thuban/branches/upstream/current/po/de.po
===================================================================
--- packages/thuban/branches/upstream/current/po/de.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/de.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1837 @@
+# German Translation for Thuban.
+# Copyright (C) 2003 Bjoern Broscheit
+# Copyright (C) 2003, 2005 Intevation GmbH
+# This file is distributed under the same license as the Thuban package.
+# Bjoern Broscheit <bjoern at intevation.de>, 2003.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 1.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2003-12-23 12:31+0100\n"
+"Last-Translator: Bernhard Herzog <bh at intevation.de>\n"
+"Language-Team: german <bjoern at intevation.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+"Thuban wurde für wxPython %(wxproj-wx)s gebaut aber wxPython hat die version "
+"%(wxPython)s"
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "keine Empfänger für Kanal %s von %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "Empfänger %s%s ist nicht verbunden mit Kanal %s von %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Warnung: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tmethod %s of %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "erstes Argument muss ein absoluter Dateiname sein"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Beide Parameter müssen einen Laufwerksbuchstaben haben"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr ""
+"Keine Implementation von get_application_dir verfügbar für diese Plattform"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr ""
+"Keine Implementation von relative_filename verfügbar für diese Plattform"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "Ungültiger Index"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Keine"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Linienfarbe"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Linienbreite: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, python-format
+msgid "Size: %s"
+msgstr "Größe: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Füllung"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Klassifikation"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "Linienbreite <1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr "size < 1"
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "DEFAULT"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "Tabelle ist nicht kompatibel mit dem Format der Shapespeicherung."
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Extension: %s"
+
+#: ../Thuban/Model/label.py:91
+#, python-format
+msgid "Number of labels: %d"
+msgstr "Anzahl der Labels: %d"
+
+#: ../Thuban/Model/label.py:92
+#, python-format
+msgid "Label Layer: %s"
+msgstr "Labelebene: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Dateiname: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Sichtbar"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Unsichtbar"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Shapes: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Ausdehnung (Breite-Länge): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Ausdehnung (Breite-Länge)"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Shapetyp: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Projektion"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Ebene '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Ungültige hexadezimal Farbspezifikation %s"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Ungültige Farbspezifikation %s"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "XML-Feld-Typ unterscheidet sich von Datenbank!"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "Klassifikationswertebereich ist keine Zahl!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Labels"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Ausdehnung (projiziert): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Karte: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"Keine GDAL Unterstützung weil das Modul '%s' nicht importiert werden kann. "
+"Python Fehler: '%s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "Konnte '%s' nicht lesen: %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Fehler in Projection '%s': %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Nicht unterstützte Gruppentyp in Klassifikation"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Dateiname:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Geändert"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "Nicht geändert"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Session: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "unbenannte Session"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "unbenannte Karte"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "Über Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Französisch"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Deutsch"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr "Ungarisch"
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Italienisch"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr "Portugiesisch (Brasilianisch)"
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Russisch"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Spanish"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- nicht verfügbar"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Aktuell verwendet:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr "\tInterne Zeichencodierung: %s\n"
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "Übersetzt für:\n"
+
+#: ../Thuban/UI/about.py:90
+msgid "Extensions:\n"
+msgstr "Extensions:\n"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr "\tKeine registriert.\n"
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr "Verwalter:\n"
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Hauptentwickler:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Entwickler:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Übersetzer:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Weitere Mitwirkende:\n"
+
+#: ../Thuban/UI/about.py:122
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"Fragen und Kommentare können an die folgenden Adressen geschickt werden:\n"
+"\tThuban Entwickler:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tThuban Mailingliste:\n"
+"\t\t<thuban-list at intevation.de>\n"
+" Thuban team at Intevation:\n"
+" <thuban at intevation.de>\n"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+"Details zu den registrierten Extensions:\n"
+"\n"
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr "Copyright %s\n"
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr "Autoren:\n"
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"Thuban ist ein Programm zur Erkundung von Geografischen Daten\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "Thuban ist lizenziert unter der GNU GPL"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Schließen"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Wählen Sie eine andere Datei für %s"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shapefiles (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Alle Dateien (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+"Habe die folgende Alternative für %s gefunden.\n"
+"%s\n"
+"\n"
+"Bitte bestätigen Sie mit Ja oder wählen Sie eine andere mit Nein"
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr "Alternativer Dateiname"
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "Thubanstartmodule können nicht importiert werden\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "Thubanstartmodul nicht verfügbar\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "~/.thuban Verzeichnis nicht vorhanden\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Ein wxPython basiertes Grafisches Benutzerinterface für das Erkunden von "
+"Geografischen Daten"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"Die aktuelle Session beinhaltet Bildebenen,\n"
+"jedoch die GDAL Bibliothek ist nicht verfügbarum diese darzustellen."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "Bibliothek nicht verfügbar"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "DB Verbindungsparameter"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Eine unbehandelte Ausnahme ist aufgetreten:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Gleichförmige Verteilung"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Eindeutige Werte"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Quantile aus Tabelle"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Benutzerdefinierter Verlauf"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Grauer Verlauf"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Roter Verlauf"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Grüner Verlauf"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Blauer Verlauf"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Grün-nach-Rot Verlauf"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Heiß-nach-Kalt Verlauf"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Erzeuge Klassifikation"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Erzeuge"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Feld: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Datentyp: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Erzeuge:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Farbschema:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Rahmenfarbe festlegen"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Ändern"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"Basiert auf die Daten aus der Tabelle und der\n"
+"Eingabewerte, können die exakten Quantile nicht erzeugt werden.\n"
+"\n"
+"Akzeptieren der geschätzten Näherung?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Probleme mit Quantile"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Min:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Max:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Aus Tabelle holen"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Anzahl der Gruppen:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Stufen:"
+
+#: ../Thuban/UI/classgen.py:647
+msgid "Available"
+msgstr "Verfügbar"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Sortieren"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Umkehren"
+
+#: ../Thuban/UI/classgen.py:687
+msgid "Use"
+msgstr "Verwenden"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Aus Tabelle holen"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Anwenden auf Wertebereich"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Anzahl der Klassen:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Start:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Ende:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr "Die Defaultgruppe kann nicht entfernt werden."
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr "Muster"
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Singleton"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Sichtbar"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "Symbol"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Wert"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Label"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Default"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Wertebereich"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Karte"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Text"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Integer"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Dezimal"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Erzeuge Klasse"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Hinzufügen"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Eine Ebene nach oben bewegen"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Eine Ebene nach unten bewegen"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Symbol bearbeiten"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Entfernen"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Feld:"
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Ebenen Einstellungen"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Ausgewählte Eigenschaften"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Vorschau:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Linienfarbe ändern"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Transparenz"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Füllfarbe ändern"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Linienbreite:"
+
+#: ../Thuban/UI/classifier.py:1242
+msgid "Size: "
+msgstr "Größe: "
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Abbrechen"
+
+#: ../Thuban/UI/colordialog.py:39
+msgid "Select Color"
+msgstr "Farbe Auswählen"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Feld"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Ebene aus Datenbank wählen"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Datenbanken"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Holen"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Tabellen"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr "ID-Spalte"
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr "Geometriespalte"
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Rechnername:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Port:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Datenbankname:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Benutzer:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Passwort:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Datenbank Verwaltung"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Datenbank Hinzufügen"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "Verbindung '%s' existiert bereits"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Datenbankverbindung entfernen"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"Die Verbindung %s\n"
+"wird noch verwendet"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Undock"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Dock"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: Interner Fehler"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Fortfahren"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr "Thuban jetzt beenden"
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr "Initialisierung noch nicht angefordert."
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr "Initialisierung erfolgreicht."
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Shape identifizieren"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Fenster Schließen"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Identifizierung Stoppen"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Verbinden"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+msgid "Select..."
+msgstr "Auswählen..."
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Tabelle:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Feld:"
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Äussere Verbindung (Erhält den linken Tabelleneintrag)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"Verbinden schlug fehl:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Info"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"Die verbundene Tabelle hat %(joined)d Zeilen aber diese muss %(needed)d "
+"Zeilen haben, um mit der ausgewählten Ebene verwendet werden zu können"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "Verbinden schlug fehl"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Tabelle: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Labelwerte"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "Titel:"
+
+#: ../Thuban/UI/layerproperties.py:65
+#, python-format
+msgid "Layer Type: %s"
+msgstr "Ebenentyp: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+msgid "Projection: None"
+msgstr "Projektion: Keine"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, python-format
+msgid "Projection: %s"
+msgstr "Projektion: %s"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Anwenden"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Zurücksetzen"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Auf die oberste Ebene bewegen"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Eine Ebene nach oben bewegen"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Eine Ebene nach unten bewegen"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Auf die unterste Ebene bewegen"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Sichtbar"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Nicht sichtbar"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Ebeneneinstellungen bearbeiten"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Unbekanntes Kommando %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "Unbekannte Kommando ID %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "Der Dialog %s ist bereits geöffnet"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+"Wählen Sie die Ebene '%s' und wählen eine Projektion mit Ebene/Projektion..."
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Beenden"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "Die Session wurde geändert! Möchten Sie diese speichern?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Öffne Session"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Speichere Session unter ..."
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Eine oder mehrere Dateien auswählen"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Ebene hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "Kann Datei nicht öffnen '%s'."
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Bilddatei wählen"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Bildebene hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Ebene aus Datenbank hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "Kann Datenbanktabelle '%s' nicht öffnen."
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "Kopie von `%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Ebenentabelle: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Kartenprojektion: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Ebenenprojektion: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Verbinde Ebene mit Tabelle"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Legende"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Öffne Tabelle"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "DBF Dateien (*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Wähle die Tabellen zum Schließen:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Tabelle schließen"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Wähle Tabellen zum Anzeigen:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Tabelle anzeigen"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Tabellen verbinden"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Wähle Tabellen zum Umbenennen:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "Tabelle umbenennen"
+
+#: ../Thuban/UI/mainwindow.py:942
+msgid "Table Title:"
+msgstr "Tabellentitel:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Map Title:"
+msgstr "Kartentitel:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Rename Map"
+msgstr "Karte Umbenennen"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Layer Title:"
+msgstr "Ebenentitel: %s"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Rename Layer"
+msgstr "Ebene Umbenennen"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&Neue Session"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Starte eine neue Session"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "&Öffne Session"
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Sessiondatei öffnen"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&Speichere Session"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "Speichere diese Session in die Datei, die geöffnet wurde von"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "Speichere Session &Unter..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Diese Session in einer neuen Datei speichern"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "Session &Baum"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "Das Analysefenster des Sessionbaums zeigen/schließen"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Legende zeigen/schließen"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "&Datenbankverbindungen"
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "Be&enden"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "Arbeiten mit Thuban beenden"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "&Über..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr ""
+"Informationen über die Autoren von Thuban, die Version und die verwendeten "
+"Module"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "Pro&jektion..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "Setze oder ändere die Kartenprojektion"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "Hine&inzoomen"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Hineinzoomen"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "Her&auszoomen"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Herauszoomen"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "&Verschieben"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Verschieben"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Identifizieren"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Identifizieren"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "&Label"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Labels hinzufügen/entfernen"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "Volle Ausdehnung"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "Zur vollen Kartenausdehnung zoomen"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "Volle Ebenenausdehnung"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "Zur vollen Ebenenausdehnung zoomen"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "Volle Auswahlausdehnung"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "Zur vollen Auswahlausdehnung zoomen"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "E&xport"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Exportiere die Karte in die Datei"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "&Drucken"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Karte drucken"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "&Umbenennen..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Karte umbenennen"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "Ebene &hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Eine neue Ebene zur Karte hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "&Bildebene hinzufügen..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Eine neue Bildebene zur Karte hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "&Datenbankebene hinzufügen..."
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "Eine neue Bildebene aus einer Datenbank zur Karte hinzufügen"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "Ebene &entfernen"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Ausgewählte Ebene entfernen"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Projektion für die ausgewählte Ebene spezifizieren"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Duplizieren"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Ausgewählte Ebene duplizieren"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "&Umbenennen..."
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Ausgewählte Ebene umbenennen"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "Eine Ebene nach &oben bewegen"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Ausgewählte Ebene eine Ebene nach oben bewegen"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "Eine Ebene nach &unten bewegen"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Ausgewählte Ebene eine Ebene nach unten bewegen"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "&Sichtbar"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "Ausgewählte Ebene ist sichtbar"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "&Nicht sichtbar"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Ausgewählte Ebene ist nicht sichtbar"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "&Zeige Tabelle"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "Die Tabelle zur ausgewählten Ebene zeigen"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Einstellungen..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "Die Einstellungen der ausgewählten Ebenen bearbeiten"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "Tabelle &verbinden..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "Verbinden und anfügen einer Tabellen zur ausgewählten Ebenen"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr "&Oben"
+
+#: ../Thuban/UI/mainwindow.py:1261
+msgid "Put selected layer to the top"
+msgstr "Ausgewählte Ebene nach oben stellen"
+
+#: ../Thuban/UI/mainwindow.py:1263
+msgid "&Bottom"
+msgstr "&Unten"
+
+#: ../Thuban/UI/mainwindow.py:1264
+msgid "Put selected layer to the bottom"
+msgstr "Ausgewählte Ebene nach unten stellen"
+
+#: ../Thuban/UI/mainwindow.py:1266
+msgid "&Visible"
+msgstr "&Sichtbar"
+
+#: ../Thuban/UI/mainwindow.py:1268
+msgid "Toggle visibility of selected layer"
+msgstr "Sichtbarkeit der ausgewählten Ebene umschalten"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "Verbindungen &lösen"
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Letzte Verbindungenoperation rückgängig machen"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&Öffnen..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Öffne eine DBF-Tabelle aus einer Datei"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&Schließen..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Schließe eine oder mehrere Tabellen von der Liste"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Umbenennen von einer oder mehreren Tabellen"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "&Zeigen..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Zeige eine oder mehrere Tabelle in einem Dialog"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&Verbinden..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Verbinde zwei Tabellen erzeuge eine neue Tabelle"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&Datei"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Karte"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "&Ebene"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Tabelle"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "&Hilfe"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "Untermenü %s existiert nicht"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Universal Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert Conic Conformal"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Geographisch"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Import..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Export..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "EPSG Anzeigen:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normal"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Veraltet"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Name:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Projektion:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<Unbekannt>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Neu"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Hinzufügen zur Liste"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Aktualisieren"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Warnungen beim Lesen von '%s':\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Import"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Warnungen"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Export"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "Der folgende Fehler trat auf:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Fehler"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "Keine Projektionen Ausgewählt:"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Quelle der Projektionen: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Mehrere Projektionen Ausgewählt"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Rotationsellipsoid"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban kennt die Parameter für\n"
+"die aktuelle Projektion nicht und\n"
+"kann daher das Konfigurationspanel \n"
+"nicht zeigen.\n"
+"\n"
+"Die nicht erkannten Parameter sind:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Breitengrad:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Längengrad:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "Falsche Ostausrichtung:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "Falsche Nordausrichtung:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Skalierungsfaktor:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Vorschlagen"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Südliche Hemisphäre"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zone:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "Kann nicht vorgeschlagen werden: Da keine Bounding Box gefunden wurde."
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Projektion: Vorschlag UTM Zone"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Standard-Parallelkreis 1:"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "Standard-Parallelkreis 2:"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Zentraler Meridian:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Geographische Breitenreferenz:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Grade"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radiant"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "Quelldaten sind in:"
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "Die gegenwärtige Kartenausdehnung liegt in der UTM Zone"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Übernehmen"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Verfügbare Projektionen"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<Keine>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (aktuell)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+"GDAL Bildinformation nicht verfügbar. Siehe Hilfe/Über... wegen Details."
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+msgid "Extent (lat-lon): None"
+msgstr "Ausdehnung (Breite-Länge): Keine"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+msgid "Image Properties"
+msgstr "Bildeigenschaften"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr "Quelle: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, python-format
+msgid "Driver: %s"
+msgstr "Treiber: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr "Größe: %ix%i"
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, python-format
+msgid "Number of Bands: %i"
+msgstr "Anzahl der Bänder: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr "Maskentyp"
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr "Opazität:"
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Ersetze Selektion"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Selektion verfeinern"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Zu Selektion hinzufügen"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Abfrage"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Selektion exportieren"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Selektion"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i Zeilen (%i ausgewählt), %i Spalten"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Exportiere Tabelle nach"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "DBF Dateien (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "CSV Dateien (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Alle Dateien (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Sitzung"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Exportiere Karte"
Added: packages/thuban/branches/upstream/current/po/es.po
===================================================================
--- packages/thuban/branches/upstream/current/po/es.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/es.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1856 @@
+# Thuban Translation File for Spanish
+# Archivo de Traducción al Castellano de Thuban
+# Copyright (C) 2003
+# This file is distributed under the same license as the Thuban package.
+# Daniel Calvelo (dcalvelo at minag.gob.pe), 2003
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 1.0Report-Msgid-Bugs-To: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2003-12-16 14:12-0500\n"
+"Last-Translator: Daniel Calvelo Aros (dcalvelo at minag.gob.pe)\n"
+"Language-Team: Thuban <thuban at intevation.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "no hay receptores para el canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "el receptor %s%s no está conectado al canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Advertencia: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tmétodo %s de %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "el primer argumento debe ser un nombre de fichero absoluto"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Ambos parámetros deben contener una letra de unidad"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr ""
+"No existe una implementación de nombre de get_application_dir para esta "
+"plataforma"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr "No existe una implementación de relative_filename para esta plataforma"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "Ãndice no válido"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Ninguno"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Color de LÃnea"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Ancho de LÃnea: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Llenado"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Clasificación"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "ancho < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "POR OMISIÃN"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "Tabla no compatible con almacén de capas"
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Extensión: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "Número de Grupos:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "Tabla: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Archivo: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Visible"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Oculto"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Elementos: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Cobertura (lat-lon): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Cobertura (lat-lon):"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Tipo de capa: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Proyección"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Capa '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Especificación hexadecimal de color %s inválida"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Especificación de color %s inválida"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "¡el tipo de campo xml es diferente del de la base de datos!"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "¡El rango de la clasificación no es un número!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Etiquetas"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Cobertura (proyectada): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Mapa: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Desconocido"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"No hay soporte para GDAL, porque el módulo '%s' no pudo ser importado. La "
+"excepción de Python fue \"%s\""
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "No se pudo leer \"%s\": %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Error en la Proyección \"%s\": %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Tipo de Grupo no implementado en la clasificación"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Archivo:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Modificado"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "No modificado"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Sesión: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "sesión sin nombre"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "mapa sin tÃtulo"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "Sobre Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Francés"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Alemán"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Italiano"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Ruso"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Castellano"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- no disponible"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Usando actualmente:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "Compilado para:\n"
+
+#: ../Thuban/UI/about.py:90
+#, fuzzy
+msgid "Extensions:\n"
+msgstr "Extensión: %s"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Programador Principal:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Programadores:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Traductores:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Otros Colaboradores\n"
+
+#: ../Thuban/UI/about.py:122
+#, fuzzy
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"EnvÃe preguntas y comentarios a las siguientes direcciones electrónicas:\n"
+"\tDesarrollo de Thuban:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tLista de difusión acerca de Thuban:\n"
+"\t\t<thuban-list at intevation.de>"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"Thuban es un programa para la exploración de datos geográficos\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "Thuban es distribuido bajo la licencia GPL de GNU"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Cerrar"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Seleccione uno o más archivos de datos"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shapefiles (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Todos (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "No se pudo importar el módulo de inicio thubanstart\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "El módulo de inicio thubanstart no está disponible\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "No existe el directorio ~/.thuban\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Esta es la Interfase Gráfica basada en wxPython para la exploración de datos "
+"geográficos"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"La sesión actual contiene capas de imagen,\n"
+"pero la biblioteca GDAL no está disponible para dibujarlas."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "Biblioteca no disponible"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "Parámetros de Conexión a Base de Datos"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Se activó una excepción no manejada:\n"
+"%s\n"
+"(por favior informe del error utilizando http://thuban.intevation.org/"
+"bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Distribución Uniforme"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Valores únicos"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Cuantiles a partir de la Tabla"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Rampa Propia"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Rampa Gris"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Rampa Roja"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Rampa Verde"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Rampa Azul"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Rampa Verde a Azul"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Rampa Cálidos a FrÃos"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Generar Clasificación"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Generar"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Tipo de Datos: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Generar:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Esquema de Colores:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Fijar Color de LÃnea"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Cambiar"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"En base a los datos de la tabla y los valores\n"
+"ingresados, no se pudo generar cuantiles exactos.\n"
+"\n"
+"¿Acepta un buen estimado? "
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Problemas en cuantiles"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Min:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Max:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Tomar de la Tabla"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Número de Grupos:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Espaciado:"
+
+#: ../Thuban/UI/classgen.py:647
+#, fuzzy
+msgid "Available"
+msgstr "- no disponible"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Ordenar"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Invertir"
+
+#: ../Thuban/UI/classgen.py:687
+#, fuzzy
+msgid "Use"
+msgstr "Usuario:"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Tomar de la Tabla"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Aplicar al Rango"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Número de Grupos:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Inicio:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Fin:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Valor Ãnico"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Visible"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "SÃmbolo"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Valor"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Etiqueta"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Por Omisión"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Rango"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Mapa"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Texto"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Entero"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Decimal"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Generar Clases"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Añadir"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Elevar"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Bajar"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Editar SÃmbolo"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Eliminar"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Campo: "
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Propiedades de la Capa"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Seleccionar Propiedades"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Previsualización:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Cambiar Color de LÃnea"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Transparente"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Cambiar Color de Llenado"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Ancho de LÃnea: "
+
+#: ../Thuban/UI/classifier.py:1242
+#, fuzzy
+msgid "Size: "
+msgstr "TÃtulo: "
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "Aceptar"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: ../Thuban/UI/colordialog.py:39
+#, fuzzy
+msgid "Select Color"
+msgstr "Selección"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Campo"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Escoja una capa de la base de datos"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Bases de Datos"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Recuperar"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Tablas"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Nombre de Host:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Puerto:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Nombre de la Base de Datos:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Usuario:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Contraseña:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Gestión de Bases de Datos"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Añadir Base de Datos"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "La conexión '%s' ya existe"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Eliminar Conexión a Base de Datos"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"La Conexión %s\n"
+"está siendo usada"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Liberar"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Estacionar"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: Error Interno"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Ejecutar"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Identificar"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Cerrar Ventana"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Desactivar Modo Identificar"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Unir"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+#, fuzzy
+msgid "Select..."
+msgstr "Selección"
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Tabla:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Campo: "
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Unión externa (conserva los registros de la tabla izquierda)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"La unión falló:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Información"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"La table que está uniendo tiene %(joined)d lÃneas pero debe tener %(needed)d "
+"lÃneas para poder ser utilizada con la capa seleccionada"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "La unión falló"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Tabla: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Valores de Etiqueta"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "TÃtulo: "
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "Tabla: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "Proyección:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "Proyección:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Probar"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Revertir"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Capa Superior"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Elevar Capa"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Bajar Capa"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Capa Inferior"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Mostrar Capa"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Ocultar Capa"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Editar Propiedades de la Capa"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Comando Desconocido %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "ID de comando desconocida %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "La Ventana de Diálogo %s ya está abierta"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Salir"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "La sesión ha sido modificada. ¿Desea guardarla?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Abrir sesión"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Guardar sesión como"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Seleccione uno o más archivos de datos"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Añadir capa"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "No se pudo abrir el fichero '%s'"
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Seleccionar un fichero de imagen"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Añadir Capa de Imagen"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Añadir Capa desde una base de datos"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "No se pudo abrir la tabla '%s'"
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "Copia de `%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Tabla: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Proyección del Mapa: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Proyección de la Capa: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Unir Capa con Tabla"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Leyenda"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Abrir Tabla"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "Archivos DBF (*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Elija qué tablas cerrar:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Cerrar Tabla"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Elija qué tablas mostrar:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Mostrar Tabla"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Unir Tablas"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Elija qué tabla renombrar:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "Cambia el nombre de la Tabla"
+
+#: ../Thuban/UI/mainwindow.py:942
+#, fuzzy
+msgid "Table Title:"
+msgstr "Tabla:"
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Map Title:"
+msgstr "TÃtulo: "
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Rename Map"
+msgstr "Cambiar el nombre del mapa"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Layer Title:"
+msgstr "Tabla: %s"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Rename Layer"
+msgstr "Elimina&r Capa"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&Nueva Sesión"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Iniciar nueva sesión"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "&Abrir Sesión..."
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Abrir un archivo de sesión"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&Guardar Sesión"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "Guardar esta sesión en el archivo del que fue abierta"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "Guardar Sesión &Como..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Guardar esta sesión en un archivo nuevo"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "A&rbol de Sesión"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "Activar/desactivar la ventana de análisis del árbol de sesión"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Activar/desactivar leyenda"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "Conexiones a Bases de &Datos..."
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "&Salir"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "Termina de trabajar con Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "&Sobre Thuban..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "Información sobre los autores, versión y módulos de Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "Pro&yección..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "Definir o cambiar la proyección del mapa"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "&Zoom+"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Cambiar a modo 'zoom+'"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "Z&oom-"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Cambiar a modo 'zoom-'"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "Des&plazar"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Cambiar a modo 'desplazar'"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Identificar"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Cambiar a modo 'identificar'"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "&Etiqueta"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Añadir/Eliminar etiquetas"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "Ãrea de &todas las capas"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "AmplÃa el mapa para cubrir el área de todas las capa"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "Ãrea de esta &Capa"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "AmplÃa el mapa para cubrir el área de la capa actual"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "Cobertura de la &Selección"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "AmplÃa el mapa para cubrir el área de la selección"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "E&xportar"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Exportar el mapa a un archivo"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "Imp&rimir"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Imprimir el mapa"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "Cambiar nomb&re..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Cambiar el nombre del mapa"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "&Añadir Capa..."
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Añadir una capa al mapa"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "Añadir Capa I&magen..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Añadir una capa imagen al mapa"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "Añadir Capa de Base de &Datos..."
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "Añadir una capa de base de datos al mapa activo"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "Elimina&r Capa"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Eliminar la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Especificar la proyección de la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Duplicar"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Duplicar la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "Cambiar nomb&re..."
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Cambia el nombre de la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "&Elevar"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Elevar de nivel la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "&Bajar"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Bajar de nivel la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "Mo&strar"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "Hacer visible la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "&Ocultar"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Ocultar la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "Mostrar Ta&bla"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "Mostrar la tabla de atributos de la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Propiedades..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "Editar las propiedades de la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "&Unir Tabla..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "Unir y agregar una tabla a la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+#, fuzzy
+msgid "Put selected layer to the top"
+msgstr "Duplicar la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1263
+#, fuzzy
+msgid "&Bottom"
+msgstr "Capa Inferior"
+
+#: ../Thuban/UI/mainwindow.py:1264
+#, fuzzy
+msgid "Put selected layer to the bottom"
+msgstr "Duplicar la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1266
+#, fuzzy
+msgid "&Visible"
+msgstr "Visible"
+
+#: ../Thuban/UI/mainwindow.py:1268
+#, fuzzy
+msgid "Toggle visibility of selected layer"
+msgstr "Elevar de nivel la capa seleccionada"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "&Desunir Tabla..."
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Deshacer la última unión"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&Abrir..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Abrir un archivo de tabla DBF"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&Cerrar..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Cerrar una o más tablas a partir de una lista"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Cambiar el nombre de una o más tablas"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "Mo&strar..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Mostrar una o más tablas"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&Unir..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Unir dos tablas en una tabla nueva"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&Archivo"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Mapa"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "&Capa"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Tabla"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "A&yuda"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "El submenu %s no existe"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Mercator Transversa"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Mercator Transversa Universal (UTM)"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert Cónica Conforme"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Geográfica"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Importar..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Exportar..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "Mostrar EPSG:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normal"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Descontinuado"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Editar"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Nombre:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Proyección:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<Desconocido>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Nueva"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Añadir a disponibles"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Actualizar"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Se detectó alertas en la lectura de \"%s\":\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Importar"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Alertas"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Exportar"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "Ocurrió el error siguiente:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Error"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "No se selccionó Proyecciones"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Fuente de la Proyección: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Se seleccionó Proyecciones múltiples"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "Internacional 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Elipsoide:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban desconoce los parámetros \n"
+"de la proyección actual y no puede \n"
+"mostrar un panel de configuración.\n"
+"\n"
+"El juego de parámetros desconocido es:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Latitud:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Longitud:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "Falso Este:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "Falso Norte:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Factor de Escala:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Proponer"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Hemisferio Sur"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zona:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "No se puede proponer: No hay una caja de contorno.XX"
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Proyección: Proponer Zona UTM"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Latitud del primer paralelo estándar"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "Latitud del segundo paralelo estándar"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Meridiano Central:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Latitud del orÃgen:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Grados"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radianes"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "Los datos originales están en: "
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "El centro del mapa actual está en zona UTM"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Tomar"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Proyecciones disponibles"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<Ninguno>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (actual)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "Cobertura (lat-lon):"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "Propiedades de la Capa"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "Número de Grupos:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Reemplazar selección"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Refinar la selección"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Añadir a la selección"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Seleccionar"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Exportar la selección"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Selección"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i lÃneas (%i seleccionadas), %i columnas"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Exportar Tabla"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "Archivos DBF (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "Archivos CSV (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Todos los archivos (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Sesión"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Exportar Mapa"
+
+#~ msgid "Type: %s"
+#~ msgstr "Tipo: %s"
+
+#~ msgid "Projection: UTM Parameters"
+#~ msgstr "Proyección: Parámetros UTM"
+
+#~ msgid "UTM Zone"
+#~ msgstr "Zona UTM"
+
+#~ msgid "Ellipsoid"
+#~ msgstr "Elipsoide"
Added: packages/thuban/branches/upstream/current/po/fr.po
===================================================================
--- packages/thuban/branches/upstream/current/po/fr.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/fr.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1856 @@
+# French translation for Thuban
+# Traduction française de Thuban
+# Copyright (C) 2003
+# This file is distributed under the same license as the Thuban package.
+# Ce fichier est distribué sous la même licence que Thuban
+# Daniel Calvelo Aros <dcalvelo at minag.gob.pe>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 1.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2003-12-16 15:12-0500\n"
+"Last-Translator: Daniel Calvelo Aros <dcalvelo at minag.gob.pe>\n"
+"Language-Team: Thuban developers <thuban at intevation.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "pas de récepteur pour le canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "le récepteur %s%s n'est pas connecté au canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Alerte: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tméthode %s de %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "le premier argument doit être un chemin d'accès absolu à un fichier"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Les deux paramètres doivent avoir une lettre d'unité"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr "Cette plateforme ne définit pas la fonction get_application_dir"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr "Cette plateforme ne définit pas la fonction relative_filename"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "indice non valable"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Néant"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Couleur de Trait"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Largeur de Trait: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "Champ: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Remplir"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Classification"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "largeur < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "DÃFAUT"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "La Table n'est pas compatible avec le dépôt de données"
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Extension: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "Nombre de Classes:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "Table: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Nom de Fichier: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Affiché"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Occulte"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Ãléments: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Extension (lat-lon): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Extension (lat-lon):"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Type: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Projection"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Couche '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Spécification de couleur héxadécimale incorrecte %s"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Spécification de couleur incorrecte %s"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "Le type de champ xml est différent de celui de la base de données!"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "Le rang de classification n'est pas un nombre!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Ãtiquettes"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Extension (projetée): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Carte: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Inconnu"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"GDAL n'est pas disponible parce que le module '%s' n'a pas pu être importé. "
+"L'exception déclenchée par Python est: '%s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "Impossible de lire \"%s\": %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Erreur dans la Projection \"%s\": %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Type de groupe non géré par la classification"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Nom de fichier:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Modifié"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "Non modifié"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Session: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "session sans nom"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "carte sans nom"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "A props de Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Français"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Allemand"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Italien"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Russe"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Espagnol"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- non disponible"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Utilise actuellement:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "Compilé pour:\n"
+
+#: ../Thuban/UI/about.py:90
+#, fuzzy
+msgid "Extensions:\n"
+msgstr "Extension: %s"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Développeur Principal:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Développeurs:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Traducteurs:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Autres Collaborateurs:\n"
+
+#: ../Thuban/UI/about.py:122
+#, fuzzy
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"Vos questions et commentaires peuvent être adressés à :\n"
+"\tDéveloppement de Thuban:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tListe de discussion sur Thuban:\n"
+"\t\t<thuban-list at intevation.de>"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"Thuban est un logiciel pour l'exploration de données géographiques\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "Thuban est distribué sous la licence GPL de GNU"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Fermer"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Choisir un ou plusieurs fichiers de données"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shapefiles (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Tous (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "N'a pu importer le module initial thubanstart\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "N'a pu trouver le module initial thubanstart\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "Le répertoire ~/.thuban n'existe pas\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Voici l'interface graphique pour l'exploration de données géographiques "
+"basée sur wxPython"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"La session actuelle contient des couches image,\n"
+"mais la bibliothèque GDAL n'est pas disponible pour les utiliser."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "Bibliothèque non disponible"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "Paramètres de Connexion à la Base de Données"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Une exception non gérée a été déclenchée:\n"
+"%s\n"
+"(veuillez faire un rapport à l'adresse http://thuban.intevation.org/"
+"bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Distribution Uniforme"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Valeurs Uniques"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Quantiles à partir de la Table"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Rampe Personnalisée"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Rampe Grise"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Rampe Rouge"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Rampe Verte"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Rampe Bleue"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Rampe du Vert au Rouge"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Rampe Chaud-et-Froid"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Générer la Classification"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Générer"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Champ: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Type de Donnée: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Générer:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Couleurs:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Couleur de Trait fixe"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Changer"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"à partir des données de la table et les valeurs indiquées,\n"
+"des quantiles exacts n'ont pas pu être générés.\n"
+"\n"
+"Acceptez-vous une approximation?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Problème de Quantiles"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Min:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Max:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Extraire de la Table"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Nombre de Groupes:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Intervale:"
+
+#: ../Thuban/UI/classgen.py:647
+#, fuzzy
+msgid "Available"
+msgstr "- non disponible"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Trier"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Inverser"
+
+#: ../Thuban/UI/classgen.py:687
+#, fuzzy
+msgid "Use"
+msgstr "Utilisateur:"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Extraire de la Table"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Appliquer à l'intervalle"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Nombre de Classes:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Début"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Fin:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Valeur unique"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Visible"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "Symbole"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Valeur"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Ãtiquette"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Défaut"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Rang"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Carte"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Texte"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Entier"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Décimal"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Génerer la Classe"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Ajouter"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Ãlever"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Descendre"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Ãditer le Symbole"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Ãliminer"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Champ: "
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Propriétés de la Couche"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Etablir les Propriétés"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Prévisualisation"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Changer la Couleur du Trait"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Transparent"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Chager la Couleur du Fond"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Largeur de Trait: "
+
+#: ../Thuban/UI/classifier.py:1242
+#, fuzzy
+msgid "Size: "
+msgstr "Titre: "
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Annuler"
+
+#: ../Thuban/UI/colordialog.py:39
+#, fuzzy
+msgid "Select Color"
+msgstr "Sélection"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Champ"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Choisir une couche dans la base de données"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Bases de Données"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Retrouver"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Tables"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Nom de l'Hôte:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Port:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Base de Données:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Utilisateur:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Mot de Passe:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Gestion de Bases de Données"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Ajouter une Base de Données"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "La connexion '%s' existe déjà "
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Elminer la connexion"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"La connexion %s\n"
+"est toujours utilisée"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Déttacher"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Attacher"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: Errur Interne"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Continuer"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Identifier"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Fermer la Fenêtre"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Suspendre le mode Identifier"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Joindre"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+#, fuzzy
+msgid "Select..."
+msgstr "Sélection"
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Table: "
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Champ: "
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Jointure extérieure (conserve les registres à gauche)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"Erreur de Jointure:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Information"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"La table à joindre possède %(joined)d lignes mais elle doit avoir %(needed)d "
+"lignes pour pouvoir être utilisée avec la couche sélectionnée"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "Erreur de jointure"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Table: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Valeur d´étiquette"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "Titre: "
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "Table: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "Projection:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "Projection:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Essayer"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Revertir"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Couche supérieure"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Ãlever la Couche"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Abaisser la Couche"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Couche inférieure"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Montrer la Couche"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Occulter la Couche"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Editer les Propriétés de la Couche"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Commande inconnue: %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "ID de commande inconnue %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "La Boîte de Dialogue %s est déjà ouverte"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Sortir"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "La session a été modifiée. Voulez-vous l'enregistrer?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Ouvrir Session"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Enregistrer Session Comme"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Choisir un ou plusieurs fichiers de données"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Ajouter une Couche"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "Impossible d'ouvrir le fichier '%s'"
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Choisir un fichier de données image"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Ajouter une Couche Image"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Ajouter une Couche de la base de données"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "Impossible d'ouvrir la base de données '%s'"
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "Copie de `%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Table: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Projection: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Projection de la Couche: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Joindre Couche avec Table"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Légende"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Ouvrir Table"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "Fichiers DBF (*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Choisissez les tables que vous voulez fermer:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Fermer Ta&ble"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Choisissez la table que vous voulez montrer:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Montrer Table"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Joindre des Tables"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Choisissez la table que vous voulez renommer:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "&Renommer Table"
+
+#: ../Thuban/UI/mainwindow.py:942
+#, fuzzy
+msgid "Table Title:"
+msgstr "Table: "
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Map Title:"
+msgstr "Titre: "
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Rename Map"
+msgstr "Renommer la carte"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Layer Title:"
+msgstr "Table: %s"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Rename Layer"
+msgstr "&Eliminer une Couche"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&Nouvelle Session"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Ãtablir une nouvelle Session"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "&Ouvrir Session..."
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Ouvrir un fichier de session"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&Enregistrer Session"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr ""
+"Enregistrer cette session dans le fichier depuis lequel elle a été ouverte"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "Enregistrer Session Co&mme..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Enregistrer cette session dans un fichier nouveau"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "&Arbre de la Session"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "Active/désactive la fenêtre d'analyse de l'arbre de session"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Active/désactive la légende"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "Connexions à Bases de &Données..."
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "&Sortir"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "Finit le travail avec Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "A &Propos..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "Information sur les auteurs, versions et modules de Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "Pro&jection..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "Définit la projection de la carte"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "&Zoom+"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Change le mode à 'zoom+'"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "Z&oom-"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Change le mode à 'zoom-'"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "Dé&placement"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Change le mode à 'déplacement'"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Identifier"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Change le mode à 'identifier'"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "&Etiquette"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Ajoute/élimine des étiquettes"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "E&xtension complète"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "Ajuste l'extension à la carte entière"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "Extension de la &Couche"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "Ajuste l'extension à celle de la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "Extension de la sélection"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "Ajuste l'extension à celle de la sélection actuelle"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "E&xporter"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Exporter la carte dans un fichier"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "I&mprimer"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Imprimer la carte"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "&Renommer..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Renommer la carte"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "&Ajouter une Couche..."
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Ajouter une nouvelle couche à la carte actuelle"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "Ajouter une Couche I&mage..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Ajouter une nouvelle couche image à la carte actuelle"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "Ajouter une Couche depuis une Base de &Données..."
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr ""
+"Ajouter une nouvelle couche à la carte actuelle depuis une base de données"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "&Eliminer une Couche"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Ãliminer la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Spécifier la projection de la couche selectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Dupliquer"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Dupliquer la couche selectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "&Renommer..."
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Change le nom de la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "Ele&ver"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Ãlève de niveau la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "&Abaisser"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Abaisser le niveau de la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "&Montrer"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "Rend visible la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "&Occulter"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Rend invisible la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "Montrer Ta&ble"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "Affiche la table de la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Propriétés..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "Change les propriétés de la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "&Joindre Table..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "Joint et rajoute una table à la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+#, fuzzy
+msgid "Put selected layer to the top"
+msgstr "Dupliquer la couche selectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1263
+#, fuzzy
+msgid "&Bottom"
+msgstr "Couche inférieure"
+
+#: ../Thuban/UI/mainwindow.py:1264
+#, fuzzy
+msgid "Put selected layer to the bottom"
+msgstr "Dupliquer la couche selectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1266
+#, fuzzy
+msgid "&Visible"
+msgstr "Visible"
+
+#: ../Thuban/UI/mainwindow.py:1268
+#, fuzzy
+msgid "Toggle visibility of selected layer"
+msgstr "Ãlève de niveau la couche sélectionnée"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "Déjoi&ndre Table..."
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Défait la dernière jointure"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&Ouvrir..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Ouvre une table depuis un fichier DBF"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&Fermer..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Ferme une ou plusieurs tables dans une liste"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Change le nom d'une ou plusieurs tables"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "&Montrer..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Montre le contenu d'une ou plusieurs tables"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&Joindre..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Définit la jointure de deux tables dans une nouvelle table"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&Fichier"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Carte"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "Couc&he"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Table"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "&Aide"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "Le sous-menu %s n'existe pas"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Marcator Transverse"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Mercator Transverse Universelle (UTM)"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert Conique Conforme"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Géographique"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Importer..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Exporter..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "Montrer EPSG:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normal"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Déconseillé"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Ãdition"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Nom:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Projection:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<Inconnu>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Nouvelle"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Ajouter à la liste"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Actualiser"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Messages d'alerte en lisant \"%s\":\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Importer"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Alertes"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Exporter"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "L'erreur suivante s'est produite:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Erreur"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "Projections non spécifiées"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Source de la Projection: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Plusieurs projections spécifiées"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Ellipsoïde:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban ne connait pas les paramètres de la \n"
+"projection actuelle et ne peut pas montrer \n"
+"un panneau de configuration.\n"
+"\n"
+"L'ensemble de paramètres inconnu est:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Latitude:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Longitude:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "Faux Est:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "Faux Nord:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Facteur d'Echelle"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Proposer"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Hémisphère Sud"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zone:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "Impossible de proposer: pas de boîte enveloppante"
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Projection: Proposer Zone UTM"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Latitude du premier parallèle standard"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "Latitude du deuxième parallèle standard"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Méridien Central:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Latitude de l'origine:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Degrés"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radians"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "Les données d'origine sont en: "
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "Le centre de l'extension actuelle de la carte appartien à la Zone UTM"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Choisir"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Projections Disponibles"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<Néant>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (actuelle)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "Extension (lat-lon):"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "Propriétés de la Couche"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "Champ: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "Nombre de Classes:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Remplacer la Sélection"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Raffiner la Sélection"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Ajouter à la Sélection"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Chercher"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Exporter la Sélection"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Sélection"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i lignes (%i selectionnées), %i colonnes"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Exporter Table Sous"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "Fichiers DBF (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "Fichiers CSV (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Tous (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Session"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Exporter la carte"
+
+#~ msgid "Type: %s"
+#~ msgstr "Type: %s"
+
+#~ msgid "Projection: UTM Parameters"
+#~ msgstr "Projection: Paramètres UTM"
+
+#~ msgid "UTM Zone"
+#~ msgstr "Zone UTM"
+
+#~ msgid "Ellipsoid"
+#~ msgstr "Ellipsoïde"
Added: packages/thuban/branches/upstream/current/po/hu.po
===================================================================
--- packages/thuban/branches/upstream/current/po/hu.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/hu.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1830 @@
+# Hungarian Translation for Thuban.
+# Copyright (C) 2004 Norbert Solymosi
+# This file is distributed under the same license as the Thuban package.
+# Norbert Solymosi <Solymosi.Norbert at aotk.szie.hu>, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 1.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2004-11-09 11:31+0100\n"
+"Last-Translator: Solymosi Norbert <Solymosi.Norbert at aotk.szie.hu>\n"
+"Language-Team: hungarian <Solymosi.Norbert at aotk.szie.hu>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+"Thuban fordításához wx %(wxproj-wx)s használtak, míg a wxPython %(wxPython)s"
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "nincsenek vevõk a csatornához %s of %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "a vevõ %s%s nem kapcsolódott a csatornájához %s ennek %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Figyelmeztetés: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\teljárás %s ehhez %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "az elsõ résznek teljes fájlnének kell lennie"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Mindkét paraméternek egy meghajtó betût kell tartalmaznia???"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr "A platformra nem elérhetõ a get_application_dir"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr "A platformra nem elérhetõ a relative_filename"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "érvénytelen index"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Nincs"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Vonalszín"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Vonalszélesség: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "Méret:"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Kitölt"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Osztályozás"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "vonalvastagság < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr "méret < 1"
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "ALAPÉRTELMEZETT"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "A tábla nem kompatibilis a shapesztorral."
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Kiterjesztés: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "Osztályok száma:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "Tábla: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Fájlnév: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Megjelenített"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Rejtett"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Alakzat: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Kiterjedés (szélesség-hosszúság): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Kiterjedés (szélesség-hosszúság): "
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Alakzat-típus: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Vetület"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Réteg '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Hibás hexadecimális színmeghatározás: '%s'."
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Hibás színmeghatározás: '%s'."
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "xml mezõ típusa különbözik az adatbázistól!"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "Az osztályozási tartomány nem szám!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Címkék"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Kiterjedés (vetületi): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Térkép: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Ismeretlen"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"Nincs GDAL támogatás, mert a '%s' modult nem lehet betölteni. Python "
+"kivétel: '%s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "Olvashatalan \"%s\": %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Hiba a vetületben \"%s\": %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Osztályozásban nem támogatott csoport típus"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Fájlnév:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Módosítva"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "Változatlan"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Munkafolyamat: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "elnevezendõ munkafolyamat"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "elnevezendõ térkép"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "Thuban névjegye"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Francia"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Német"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Olasz"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr "Portugál (Brazil)"
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Orosz"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Spanyol"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- nem elérhetõ"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Jelenleg használt:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "A fordításhoz alapul szolgált:\n"
+
+#: ../Thuban/UI/about.py:90
+msgid "Extensions:\n"
+msgstr "Kiterjesztések:\n"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr "\tNincs regisztrálva.\n"
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Vezetõ fejlesztõ:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Fejlesztõk:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Fordítók:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Egyéb közremûködõk:\n"
+
+#: ../Thuban/UI/about.py:122
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"A felmerülõ kérdéseket és észrevételeket a következõ címre várjuk:\n"
+"\tÁltalános lista (nyilvános):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tFejlesztõ lista (nyilvános):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tIntevation Thuban csoportja:\n"
+"\t\t<thuban at intevation.de>\n"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+"A regisztrált kiterjesztések részletei:\n"
+"\n"
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr "Copyright: %s\n"
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr "Szerzõk:\n"
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"A Thuban földrajzi adatok elemzését szolgáló szoftver.\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "A Thuban-ra a GNU GPL liszensz feltételei vonatkoznak"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Bezár"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Válasszon ki egy vagy több adatfájlt"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shape-fájlok (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Minden fájlt (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "A thubanstart modul nem beolvasható\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "Nincs elérhetõ thubanstart modul\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "Nincs ~/.thuban könyvtár\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Ez a wxPython alapú grafikus felhasználói felület a földrajzi adatok "
+"elemzéséhez"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"A jelenlegi munkafolyamat tartalmaz kép-réteget,\n"
+"de GDAL könyvtár nem elérhetõ a megjelenítéséhez."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "A könyvtár nem létezik."
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "Adatbázis-kapcsolati paraméterek"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Nem kezelt kivétel jelentkezett:\n"
+"%s\n"
+"(légyszi küldjed ide: http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Egyenletes eloszlás"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Egyedi értékek"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Kvantilisek a táblázatból"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Egyéni küszöb"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Szürke küszöb"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Vörös küszöb"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Zöld küszöb"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Kék küszöb"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Zöld-Vörös küszöb"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Forró-Hideg küszöb"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Osztályozás generálása"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Létrehozás"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Mezõ: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Adattípus: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Generálás:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Színséma:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Határszín rögzítése"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Módosít"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"Az egzakt kvantilisek nem generálhatók a\n"
+"táblázatból származó és beolvasott adatokra alapozva.\n"
+"\n"
+"Elfogadsz egy jó közelítést?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Probléma a kvantilisekkel"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Minimum:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Maximum:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Kigyûjt táblából"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Csoportok száma:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Lépés:"
+
+#: ../Thuban/UI/classgen.py:647
+msgid "Available"
+msgstr "Elérhetõ"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Rendez"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Vissza"
+
+#: ../Thuban/UI/classgen.py:687
+msgid "Use"
+msgstr "Használ"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Kigyûjt táblából"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Tartományhoz igazít"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Osztályok száma:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Kezdet:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Vég:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Singleton"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Látható"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "Szimbólum"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Érték"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Címke"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Alapértelmezett"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Tartomány"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Térkép"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Szöveg"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Egész szám"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Decimális"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Osztálygenerálás"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Hozzáad"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Mozgatás fel"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Mozgatás le"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Szimbólum beállítása"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Töröl"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Mezõ:"
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Réteg-tulajdonságok"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Tulajdonságok kiválasztása"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Elõnézet:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Vonal színének megváltoztatása"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Átlátszó"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Kitöltõ szín beállítása"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Vonalvastagság:"
+
+#: ../Thuban/UI/classifier.py:1242
+msgid "Size: "
+msgstr "Méret:"
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Mégsem"
+
+#: ../Thuban/UI/colordialog.py:39
+msgid "Select Color"
+msgstr "Szín kiválasztása"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Mezõ"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Réteg választása adatbázisból"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Adatbázisok"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Kigyûjt"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Táblák"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr "Azonosító oszlop"
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr "Geometrikus oszlop"
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Gazda:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Kapu:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Adatbázis neve:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Felhasználó:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Jelszó:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Adatbázis-kezelés"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Adatbázis hozzáadása"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "A '%s' kapcsolat már létezik"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Adatbázis-kapcsolat eltávolítása"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"A kapcsolat %s\n"
+"még használatban van."
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Felold"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Dokkol"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: Belsõ Hiba"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Tovább"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr "Kilépés a Thubanból most"
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Alakzat azonosítása"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Ablak bezárása"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Azonosító módot befejez"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Összekapcsolás"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+msgid "Select..."
+msgstr "Kiválaszt..."
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Tábla:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Mezõ:"
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Külsõ illesztés (a bal tábla rekordjait megtartja)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"Az összekapcsolás sikertelen:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Információ"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"Az kapcsolt táblának %(joined)d sora van, de %(needed)d sorra van szükség a "
+"kijelölt réteggel való használatához"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "Az összekapcsolás sikertelen"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Tábla: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Címke értékek"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "Cím: "
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "Réteg-tábla: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "Vetület:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "Vetület:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Próba"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Visszaállítás"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Legfelsõ réteg"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Réteg feljebb"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Réteg lejjebb"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Legalsó réteg"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Réteg megjelenítése"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Réteg elrejtése"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Réteg tulajdonságainak szerkesztése"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Ismeretlen parancs %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "Ismeretlen parancs ID %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "A %s ablak már nyitva van"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Kilép"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "A munkafolymat neve megváltozott. Mentsük?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Munkafolyamat megnyitása"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Munkafolyamat mentése másként"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Válasszon ki egy vagy több adatfájlt"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Réteg hozzáadása"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "Nem tudom megnyitni a(z) '%s' fájlt."
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Képfájl kiválasztása"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Kép-réteg hozzáadása"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Réteg hozzáadása adatbázisból"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "A(z) '%s' adatbázis-táblát nem lehet megnyitni."
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "`%s' másolása"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Réteg-tábla: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Térkép vetülete: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Réteg vetülete: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Réteg összekapcsolása táblával"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Jelmagyarázat"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Tábla megnyitása"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "DBF-fájlok(*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Tábla kiválasztása bezárásra:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Tábla bezárása"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Tábla kiválasztása megjelenítésre:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Tábla mutat"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Táblák összekapcsolása"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Tábla kiválasztása átnevezésre:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "Tábla átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:942
+msgid "Table Title:"
+msgstr "Tábla címe:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Map Title:"
+msgstr "Térkép címe:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Rename Map"
+msgstr "Térkép átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Layer Title:"
+msgstr "Réteg címe:"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Rename Layer"
+msgstr "Réteg átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "Új mu&nkafolyamat"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Új munkafolyamat indul"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "Munkaf&olyamat megnyitása..."
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Munkafolyamat-fájl megnyitása"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "Munkafolyamat menté&se"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "Mentsed ezt a munkafolyamatot abba a fájlba, amibõl meg lett nyitva"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "Munk&afolyamat mentése másként"
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Munkafolyamat mentése új fájlba"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "Munkafolyamat &története"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "A munkafolyamat-fájának elmzésére szolgáló ablak ki/bekapcsolója"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Segédszövegek ki- és bekapcsolása"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "A&datbázis kapcsolatok"
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "&Kilép"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "A Thuban munkának befelyezése"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "&Névjegy..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "Információ a Thuban alkotóiról, verziójáról és moduljairól"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "&Vetület"
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "A térkép vetületének beállítása"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "&Nagyítás"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Nagyításra váltás"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "&Kicsinyítés"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Kicsinyítésre váltás"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "&Mozgat"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Mozgatásra váltás"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Azonosít"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Azonosításra váltás"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "&Címke"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Címke hozzáadása/eltávolítása"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "&Teljes terjedelem"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "Méretezés a térkép teljes kiterjedésére"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "&Réteg teljes terjedelem"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "Méretezés a réteg teljes kiterjedésére"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "&Kijelölés teljes terjedelemben"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "Méretezés a kijelöltek teljes kiterjedésére"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "E&xportálás..."
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Térkép exportálása fájlba"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "&Nyomtat"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Térkép nyomtatása"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "&Átnevez..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Térkép átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "&Réteg hozzáadása"
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Réteg hozzáadása a térképhez"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "Kép-réteg hozzáadása..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Új kép-réteg hozzáadása a térképhez"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "Adatbázis-réteg hozzáadása..."
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "Az aktív térképhez új adatbázis-rteg hozzáadása"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "&Réteg eltávolítása"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Kijelölt réteg eltávolítása"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Határozza meg a kiválasztott réteg vetületét"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Kettõzés"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Kijelölt réteg megkettõzése"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "Át&nevezés"
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Kijelölt réteg átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "Fel&emelés"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Kijelölt réteg feljebb"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "&Lejjebb"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Kijeölt réteg lejjedd"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "Meg&jelenítés"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "A kijelölt réteg látható"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "El&rejtés"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Kiválasztott réteg elfedése"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "Tá&bla mutat"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "A kijelölt réteg tábláját mutat"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Tulajdonságok..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "A kijelölt réteg jellemzõinek szerkesztése."
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "Tábla össz&ekapcsolás..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "A kiválasztott réteghez tábla illesztése és kapcsolása"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr "&Legfelsõ"
+
+#: ../Thuban/UI/mainwindow.py:1261
+msgid "Put selected layer to the top"
+msgstr "Kijelölt réteget a tetejére"
+
+#: ../Thuban/UI/mainwindow.py:1263
+msgid "&Bottom"
+msgstr "&Alap"
+
+#: ../Thuban/UI/mainwindow.py:1264
+msgid "Put selected layer to the bottom"
+msgstr "Kijelölt réteget a legalulra"
+
+#: ../Thuban/UI/mainwindow.py:1266
+msgid "&Visible"
+msgstr "&Látható"
+
+#: ../Thuban/UI/mainwindow.py:1268
+msgid "Toggle visibility of selected layer"
+msgstr "A kijelölt réteg láthatóságának kapcsolója?"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "Tábla le&választása..."
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Az utolsó összekapcsolási mûvelet visszavonása"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&Megnyit..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Egy DBF-fájl megnyitása fájlból"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&Bezár..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Egy vagy több tábla bezárása a listából"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Egy vagy több tábla átnevezése"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "&Megjelenít..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Egy vagy több tábla mutatása..."
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&Kapcsolódás..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Két összekapcsolt tábla egy újat eredményez"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&Fájl"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Térkép"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "&Réteg"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Táblázat"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "&Súgó"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "A(z) '%s' almenû nem létezik"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Universal Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert féle kúpszeletes"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Földrajzi"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Importálás..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Exportálás..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "EPSG mutat:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normál"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Érvénytelenített"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Szerkesztés"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Név:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Vetület:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<ismeretlen>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Új"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Hozzáadás a listához"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Frissítés"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Fájlbeolvasási hiba \"%s\":\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Importálás"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Figyelmeztetések"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Exportálás"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "A következõ hiba történt:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Hiba"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "Nem lett kiválasztva vetület"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Vetület forrása: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Több vetülett lett kiválasztva"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Ellipszoid:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"A Thuban nem ismeri a jelenlegi vetület\n"
+"paramétereit és nem tudja megjeleníteni\n"
+"a konfigurációs panelt.\n"
+"\n"
+"A paraméterek nem azonosított készlete:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Szélesség:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Hosszúság:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "A középpont keleti irányú koordinátája:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "A középpont északi irányú koordinátája:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Skála tényezõ:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Ajánlat"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Déli félteke"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zóna:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "Nincs ajánlat: Nem található határoló doboz."
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Vetület: javasolt UTM Zóna"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Az elsõ standard párhuzamos szélessége:"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "A második standard párhuzamos szélessége:"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Centralis Meridián:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Szélesség:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Fok"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radián"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "A forrásadat:"
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "Az aktuális térkép kiterjedésének közepe UTM Zónába esik"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Vidd"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Elérhetõ vetületek"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<semmi>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (jelenlegi) "
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "Kiterjedés (szélesség-hosszúság): "
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "Réteg-tulajdonságok"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "Mezõ: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, fuzzy, python-format
+msgid "Size: %ix%i"
+msgstr "Méret:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "Osztályok száma:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Kijelölés megszüntetése"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Kijelölés finomítása"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Hozzáadás a kijelöléshez"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Lekérdezés"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Kijelöltek exportálása"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Kijelölés"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i sor (%i kijelölt), %i oszlop"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Tábla exportálása"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "DBF-fájlok(*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "CSV-fájlok (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Minden fájlt (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Munkafolyamat"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Térkép exportálása"
+
+#~ msgid "Type: %s"
+#~ msgstr "Típus: %s"
Added: packages/thuban/branches/upstream/current/po/it.po
===================================================================
--- packages/thuban/branches/upstream/current/po/it.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/it.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1869 @@
+# Italian Translations for Thuban
+# Copyright (C) 2003 Maurizio Napolitano.
+# Maurizio Napolitano <napo at itc.it>, 2003.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: it\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2003-12-22 23:09+0100\n"
+"Last-Translator: Maurizio Napolitano <napo at itc.it>\n"
+"Language-Team: <thuban at intevation.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.0.2\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "nessun ricevente per il canale %s di %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "Il ricevente %s%s non è connesso al canale %s di %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Attenzione: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tmetodo %s di %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "Il primo argomento deve essere un nome di file univoco"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Entrambi i parametri devono avere una lettera di unità "
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr ""
+"Nessuna implementazione per get_application_dir disponibile per questa "
+"piattaforma"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr ""
+"Nessuna implementazione per relative_filename disponibile per questa "
+"piattaforma"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "indice non valido"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Nessuno"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Colore linea"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Dimensione linea: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Riempimento"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Classificazione"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "dimensione linea < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "PREDEFINITO"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "Tabella non compatibile con l'archivio del vettoriale"
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Estensione: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "Numero di classi:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "Tabella: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Nome file: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Visualizzato"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Nascosto"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Vettoriali: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Estensione (lat-lon): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Estensione (lat-lon):"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Tipo vettoriale: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Proiezione"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Livello '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Valore esadecimale del colore errato %s"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Errato valore di colore %s"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "il campo XML differisce da quello del database"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "La gamma di classificazione non è un numero!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Etichette"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Estensione (proiettata): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Mappa: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Sconosciuto"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"Nessun supporto GDAL in quanto il modulo '%s' non può essere importato. "
+"Eccezione python: '%s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "Impossibile leggere \"%s\": %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Errore nella proiezione \"%s\": %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Gruppo di classificazione non supportato"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Nome file:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Modificato"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "Non modificato"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Sessione: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "sessione senza nome"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "mappa senza nome"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "Informazioni su Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Francese"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Tedesco"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Italiano"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Russo"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Spagnolo"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- non disponibile"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Attualmente in uso:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "Compilato per:\n"
+
+#: ../Thuban/UI/about.py:90
+#, fuzzy
+msgid "Extensions:\n"
+msgstr "Estensione: %s"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Sviluppatore capo: \n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Sviluppatori:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Traduttori:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Altri collaboratori:\n"
+
+#: ../Thuban/UI/about.py:122
+#, fuzzy
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"Domande e commenti possono essere spediti ai seguenti indirizzi:\n"
+"\tSviluppatori Thuban:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tThuban mailing list:\n"
+"\t\t<thuban-list at intevation.de>"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"Thuban è un programma per esplorare dati geografici.\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "Thuban è distribuito sotto licenza GNU GPL"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Chiudi"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Selezione uno o più file di dati"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "File shape (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Tutti i file (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "Impossibile importare il modulo thubanstart\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "Nessun modulo thubanstart disponibile\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "Directory ~/.thuban inesistente\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Thuban: l'interfaccia grafica per visualizzare i dati geografici basata su "
+"wxPython"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"La sessione corrente fa uso di livelli immagine,\n"
+"ma la libreria GDAL non è disponibile per visualizzarli."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "Libreria non disponibile"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "Parametri di connessione al DB"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Si è verificata una eccezione non prevista:\n"
+"%s\n"
+"(per piacere segnala l'errore a http://thuban.intevation.org/bugtracker."
+"html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Distribuzione uniforme"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Valori univoci"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Quantili per la tabella"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Scala personalizzata"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Scala di grigi"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Scala di rossi"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Scala di verdi"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Scala di blu"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Scala da verde a rossa"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Scala da freddo a caldo"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Genera la classificazione"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Genera"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Tipo di dato: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Genera:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Schema colore:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Fissa il colore del bordo"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Cambia"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"Basato sui dati della tabella e i valori\n"
+"di input, i quantili esatti non possono essere generati.\n"
+"\n"
+"Accetti una stima chiusa?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Problemi con i quantili"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Min:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Max:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Recupera dalla tabella"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Numero di gruppi:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Passo:"
+
+#: ../Thuban/UI/classgen.py:647
+#, fuzzy
+msgid "Available"
+msgstr "- non disponibile"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Ordina"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Inverti"
+
+#: ../Thuban/UI/classgen.py:687
+#, fuzzy
+msgid "Use"
+msgstr "Utente:"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Recupera dalla tabella"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Applica all'intervallo"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Numero di classi:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Avvia:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Fine:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Singleton"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Visibile"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "Simbolo"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Valore"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Etichetta"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Predefinito"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Intervallo"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Mappa"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Testo"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Intero"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Decimale"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Genera classe"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Aggiungi"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Sposta in alto"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Sposta in basso"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Modifica simbolo"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Rimuovi"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Campo:"
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Proprietà livello"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Scegli proprietà "
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Anteprima:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Cambia colore linea"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Trasparente"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Cambia colore riempimento"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Dimensioni linea:"
+
+#: ../Thuban/UI/classifier.py:1242
+#, fuzzy
+msgid "Size: "
+msgstr "Titolo:"
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Cancella"
+
+#: ../Thuban/UI/colordialog.py:39
+#, fuzzy
+msgid "Select Color"
+msgstr "Selezione"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Campo"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Seleziona il livello dal database"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Database"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Recupera"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Tabelle"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Nome del server:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Porta:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Nome del database:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Utente:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Password:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Gestione del database"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Aggiungi database"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "La connessione '%s' è già in uso"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Elimina la connessione al database"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"La connessione %s\n"
+"è attualmente in uso"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Elimina dal pannello"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Aggiungi al pannello"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: errore interno"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Continua"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Identifica geometria"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Chiudi finestra"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Fine identificazione elemento"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Unisci"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+#, fuzzy
+msgid "Select..."
+msgstr "Selezione"
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Tabella:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Campo:"
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Unione esterna (conserva i valori della tabella di sinistra)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"Unione fallita:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Informazioni"
+
+#: ../Thuban/UI/join.py:195
+#, fuzzy, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"La tabella ha unito % righe ma ha bisogno di altre % righe per essere usato "
+"con il livello selezionato"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "Unione fallita"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Tabella: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Valori per le etichette"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "Titolo:"
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "Tabella del livello: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "Proiezione:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "Proiezione:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Prova"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Annulla"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Sposta in cima"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Sposta sopra"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Sposta sotto"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Sposta in fondo"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Mostra livello"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Nascondi livello"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Modifica proprietà del livello"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Comando sconosciuto %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "ID comando sconosciuto %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "Esiste già una finestra di dialogo con nome %s"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Esci"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "La sessione è stata modificata. Vuoi salvarla?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Apri sessione"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Salva sessione con nome"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Selezione uno o più file di dati"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Aggiungi un livello"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "Impossibile aprire il file '%s'"
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Scegli un file immagine"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Aggiungi un livello immagine"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Aggiungi un livello dal database"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "Impossibile aprire la tabella '%s' dal database"
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "Copia di '%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Tabella del livello: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Proiezione mappa: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Proiezione livello: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Unisci il livello con la tabella"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Legenda"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Apri tabella"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "File DBF (*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Seleziona le tabelle da chiudere:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Chiudi tabella"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Seleziona la tabella da mostrare"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Mostra tabella"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Unisci tabelle"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Seleziona la tabella da rinominare:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "Rinomina tabella"
+
+#: ../Thuban/UI/mainwindow.py:942
+#, fuzzy
+msgid "Table Title:"
+msgstr "Tabella:"
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Map Title:"
+msgstr "Titolo:"
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Rename Map"
+msgstr "Rinomina la mappa"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Layer Title:"
+msgstr "Tabella del livello: %s"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Rename Layer"
+msgstr "&Rimuovi livello"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&Nuova sessione"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Comincia una nuova sessione"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "Apri sessi&one"
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Apri un file sessione"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&Salva sessione"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "Salva questa sessione nel file d'origine"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "Salv&a sessione come..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Sava la sessione corrente in un nuovo file"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "Al&bero della sessione"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "Mostra/Nascondi la finestra con l'analisi dell'albero della sessione"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Mostra/Nascondi legenda"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "Connetti &database..."
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "E&sci"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "Concludi il lavoro con Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "Inform&azioni..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "Informazioni sugli autori di Thuban, versione e moduli"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "Pro&iezione..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "Definisci o cambia la proiezione della mappa"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "&Zoom in"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Zoom in della mappa"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "Zoom &out"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Zoom out della mappa"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "S&posta"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Sposta la mappa"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Identifica"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Identifica elemento"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "&Etichetta"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Aggiungi/Rimuovi etichette"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "Estensione &massima"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "Zoom all'estensione massima della mappa"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "Estensione massima &livello"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "Zoom all'estensione massima del livello"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "Estensione all'elemento &selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "Zoom all'estensione del elemento selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "Es&porta"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Esporta la mappa in un file"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "Stam&pa"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Stampa la mappa"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "Ri&nomina..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Rinomina la mappa"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "Aggiungi un &vettoriale"
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Aggiungi un nuovo livello alla mappa"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "Aggiungi un livello &immagine"
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Aggiunge un nuovo livello immagine alla mappa"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "Aggiungi un livello dal &database..."
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "Aggiungi un nuovo livello dal database alla mappa in uso"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "&Rimuovi livello"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Rimuove il livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Specifica la proiezione del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Duplica"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Crea una copia del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "Ri&nomina"
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Rinomina il livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "Al&za"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Alza il livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "A&bbassa"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Abbassa il livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "&Mostra"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "Rendi i livello selezionato visibile"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "&Nascondi"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Rendi il livello invisibile"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "Mostra ta&bella"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "Mostra la tabella del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Proprietà ..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "Modifica proprietà del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "&Unisci tabella..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "Unisci e collega una tabella al livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+#, fuzzy
+msgid "Put selected layer to the top"
+msgstr "Crea una copia del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1263
+#, fuzzy
+msgid "&Bottom"
+msgstr "Sposta in fondo"
+
+#: ../Thuban/UI/mainwindow.py:1264
+#, fuzzy
+msgid "Put selected layer to the bottom"
+msgstr "Crea una copia del livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1266
+#, fuzzy
+msgid "&Visible"
+msgstr "Visibile"
+
+#: ../Thuban/UI/mainwindow.py:1268
+#, fuzzy
+msgid "Toggle visibility of selected layer"
+msgstr "Alza il livello selezionato"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "&Separa tabella..."
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Annulla l'ultima operazione di unione "
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&Apri..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Apri una tabella DBF da file"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&Chiudi..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Chiudi una o più tabelle dalla lista"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Rinomina una o più tabelle dalla lista"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "&Mostra..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Mostra una o più tabelle in una finestra"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&Unisci..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Unisci due tabelle creandone una nuova"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&File"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Mappa"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "&Livello"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Tabella"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "&Aiuto"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "Il sottomenu %s non esiste"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Mercatore Transversa"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Mercatore Transversa Universale"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert conica conforme"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Geografica"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Importa..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Esporta..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "Mostra EPSG:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normale"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Deprecato"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Modifica"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Nome:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Proiezione:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<Sconosciuto>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Nuovo"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Aggiungi alla lista"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Aggiorna"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Avvertimenti durante la lettura di \"%s\":\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Importa"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Avvertimenti"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Esporta"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "Si è verificato il seguente errore:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Errore"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "Non sono state selezionate proiezioni"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Sorgente della proiezione: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Proiezioni multiple selezionate"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Ellissoide:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban non è in grado di riconoscere i parametri\n"
+"dell'attuale proizione e quindi non puòn mostrare un pannello di "
+"configurazione\n"
+"\n"
+"L'insieme non identificato di parametri è:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Latitudine:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Longitudine:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "Falso est:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "Falso nord:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Fattore di scala:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Proponi"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Emisfero meridionale"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zona:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr ""
+"non riesco a proporre: non è possibile trovare un rettangolo di confine"
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Proiezione: proponi zona UTM"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Latitudine del primo parallelo standard:"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "Latitutidine del secondo parallelo standard:"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Meridiano centrale:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Latitudine di origine:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Gradi"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radianti"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "La sorgente dati è in: "
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "L'attuale centro dell'estensione corrente della mappa è nella zona UTM"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Prendi"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Proiezioni disponibili"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<Nulla>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (attuale)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "Estensione (lat-lon):"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "Proprietà livello"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "Numero di classi:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Sostituisci la selezione"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Redefinisci selezione"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Aggiungi alla selezione"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Interroga"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Esporta selezione"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Selezione"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i righe (%i selezionate), %i colonne"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Esporta la tabella in"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "File DBF (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "File CSV (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Tutti i file (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Sessione"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Esporta mappa"
+
+#~ msgid "Type: %s"
+#~ msgstr "Tipo: %s"
+
+#~ msgid "Projection: UTM Parameters"
+#~ msgstr "Proiezione: parametri UTM"
+
+#~ msgid "UTM Zone"
+#~ msgstr "Zona UTM"
+
+#~ msgid "Ellipsoid"
+#~ msgstr "Ellissoide"
+
+#~ msgid "Based on the data from the table and the input\n"
+#~ msgstr "Basato dai dati recuperati dalla tabella e dall'input\n"
+
+#~ msgid "Select a data file"
+#~ msgstr "Scegli un file di dati"
+
+#~ msgid "Thuban does not know the parameters for the "
+#~ msgstr "Thuban non conosce i parametri per "
+
+#~ msgid "Unhandled shape type %s"
+#~ msgstr "Tipo di geometria non supporta %s"
Added: packages/thuban/branches/upstream/current/po/pt_BR.po
===================================================================
--- packages/thuban/branches/upstream/current/po/pt_BR.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/pt_BR.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1849 @@
+# Thuban Translation File for Brazilian Portuguese
+# Arquivo de Tradução do Thuban para o Português Brasileiro
+# Copyright (C) 2004
+# This file is distributed under the same license as the Thuban package.
+# Eduardo Patto Kanegae <eduardo at consultoria.eti.br>, 2004.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 1.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2004-01-15 16:07+0300\n"
+"Last-Translator: Eduardo Patto Kanegae <eduardo at consultoria.eti.br>\n"
+"Language-Team: Thuban <thuban at intevation.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "nenhum receptor para o canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "receptor %s%s não está conectado ao canal %s de %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "Aviso: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tmétodo %s de %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "primeiro argumento deve ser um nome absoluto de arquivo"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "Ambos os parâmetros devem ter uma letra de drive"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr ""
+"Nenhuma implementação de get_application_dir disponível para a plataforma"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr ""
+"Nenhuma implementação de relative_filename disponível para a plataforma"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "índice inválido"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "Nenhum"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "Cor da Linha"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "Espessura da Linha: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "Preenchimento"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "Classificação"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "espessura da linha < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "PADRÃO"
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "Tabela não compatível com a base de shapes"
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "Extensão: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "Número de Classes:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "Tabela: %s"
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "Arquivo: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "Visível"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "Oculto"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Shapes: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "Retângulo envolvente (lat-lon): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "Retângulo envolvente (lat-lon):"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Tipo de Shape: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "Projeção"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "Camada '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "Especificação de cor hexadecimal inválida %s"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "Especificação de cor inválida %s"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "tipo do campo xml difere do banco de dados"
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "Faixa de classificação não é um número"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "Rótulos"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "Retângulo envolvente (projetado): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "Mapa: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "Desconhecido"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"Sem suporte a GDAL porque o módulo '%s' não pôde ser importado. Python "
+"exception: '%s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "Impossível ler \"%s\": %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "Erro na projeção \"%s\": %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "Tipo de grupo não suportado na classificação"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "Arquivo:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "Modificado"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "Não modificado"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "Sessão: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "sessão sem nome"
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "map sem nome"
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "Sobre o Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "Francês"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "Alemão"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "Italiano"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "Russo"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "Espanhol"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- não disponível"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "Atualmente usando:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "Compilador por:\n"
+
+#: ../Thuban/UI/about.py:90
+#, fuzzy
+msgid "Extensions:\n"
+msgstr "Extensão: %s"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "Programador líder:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "Programadores:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "Tradutores:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "Outros contribuintes:\n"
+
+#: ../Thuban/UI/about.py:122
+#, fuzzy
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"Questões e comentários podem ser enviados aos seguintes endereços:\n"
+"\tProgramadores do Thuban:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tLista de discussão Thuban:\n"
+"\t\t<thuban-list at intevation.de>"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"O Thuban é um programa para exploração de dados geográficos.\n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "O Thuban é licensiado sobre os termos da GNU GPL"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "Fechar"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "Selecione um ou mais arquivos"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shapefiles (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "Todos arquivos (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "Impossível importar o módulo thubanstart\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "Módulo thubanstart não disponível\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "Diretório ~/.thuban não encontrado\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"Este programa é uma Interface Gráfica de Usuário, baseado no wxPython, para "
+"exploração de dados geográficos"
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"A sessão atual contém camadas de Imagens,\n"
+"todavia a biblioteca GDAL não está disponível para desenhá-los."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "Biblioteca não disponível"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "Parâmetros de Conexão com o Banco de Dados"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"Uma exceção não prevista ocorreu:\n"
+"%s\n"
+"(por favor reporte o erro em http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "Distribuição uniforma"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "Valores únicos"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "Quantis da Tabela"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "Graduação Customizada"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "Graduação Cinza"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "Graduação Vermelho"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "Graduação Verde"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "Graduação Azul"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "Graduação Verde-para-Vermelho"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "Graduação Quente-para-Frio"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "Criar Classificação"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "Criar"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "Tipo de Dados: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "Criar:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "Esquema de Cores:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "Cor da Borda Fixa"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "Alterar"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"Com base nos dados da tabela e nos values\n"
+"de entrada, os quantis exatos não puderam ser criados.\n"
+"\n"
+"Aceitar um estimativa próxima?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "Problema com os Quantis"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "Mín:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "Máx:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "Recuperar da Tabela"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "Número de Grupos:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "Incremento:"
+
+#: ../Thuban/UI/classgen.py:647
+#, fuzzy
+msgid "Available"
+msgstr "- não disponível"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "Ordenar"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "Contrário"
+
+#: ../Thuban/UI/classgen.py:687
+#, fuzzy
+msgid "Use"
+msgstr "Usuário:"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "Recuperar da Tabela"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "Aplicar para a Faixa"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "Número de Classes:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "Início:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "Fim:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "Curinga"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "Visível"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "Símbolo"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "Valor"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "Rótulo"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "Padrão"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "Faixa"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "Mapa"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "Texto"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "Inteiro"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "Decimal"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "Criar Classe"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "Adicionar"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "Mover para Cima"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "Mover para Baixo"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "Editar Símbolo"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "Remover"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "Campo: "
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "Propriedades da Camada"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "Selecionar Propriedades"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "Pré-visualizar:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "Alterar Cor da Linha"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "Transparente"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "Alterar Cor do Preenchimento"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "Espessura da Linha:"
+
+#: ../Thuban/UI/classifier.py:1242
+#, fuzzy
+msgid "Size: "
+msgstr "Título: "
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: ../Thuban/UI/colordialog.py:39
+#, fuzzy
+msgid "Select Color"
+msgstr "Seleção"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "Campo"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "Selecione a camada do banco de dados"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "Bancos de Dados"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "Recuperar"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "Tabelas"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "Nome do servidor:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "Porta:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "Nome do Banco de Dados:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "Usuário:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "Senha:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "Gerenciamento de Banco de Dados"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "Adicionar Banco de Dados"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "A Conexão '%s' já existe"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "Remover Conexão com Banco de Dados"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"A conexão %s\n"
+"ainda está em uso"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "Desancorar"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "Ancorar"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: Erro Interno"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "Prosseguir"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "Identificar Item"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "Fechar Janela"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "Para modo de identificação"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "Ligação"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+msgid "Select..."
+msgstr "Selecione..."
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "Tabela:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "Campo:"
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "Outer Join (preserva os registros da tabela da esquerda)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"Ligação falhou:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "Informação"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"A tabela ligada(joined) possui %(joined)d registros mas deve ter %(needed)d "
+"registros para serusada com a camada selecionada"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "Ligação Falhou"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr "Tabela: %s"
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "Valores dos Rótulos"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "Título: "
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "Tabela da Camada: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "Projeção:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "Projeção:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "Tentar"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "Reverter"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "Camada Superior"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "Trazer Camada para cima"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "Trazer Camada para baixo"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "Camada Inferior"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "Exibir Camada"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "Ocultar Camada"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "Editar Propriedades da Camada"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr "Comando desconhecido %s"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr "ID de comando desconhecido %d"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "A caixa de Diálog %s ainda está aberta"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "Sair"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "A sessão foi modificada. Você deseja salvá-la?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "Abrir Sessão"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "Salvar Sessão como"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "Selecione um ou mais arquivos"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "Adicionar Camada"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr "Não foi possível abrir o arquivo '%s'."
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "Selecione um arquivo de imagem"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "Adicionar Camada de Imagem"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "Adicionar Camada do banco de dados"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr "Não foi possível abrir a tabela '%s'"
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "Cópia de `%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "Tabela da Camada: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "Projeção do Mapa: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "Projeção do Layer: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "Ligar Camada com Tabela"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "Legenda"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "Abrir Tabela"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "Arquivos DBF (*.dbf)"
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "Escolha as tabelas para fechar:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "Fechar Tabela"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "Escolha a tabela para exibir:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "Exibir Tabela"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "Ligar Tabelas"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "Escolha a tabela a renomear:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "Renomear Tabela"
+
+#: ../Thuban/UI/mainwindow.py:942
+msgid "Table Title:"
+msgstr "Título da Tabela:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Map Title:"
+msgstr "Título do Mapa:"
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Rename Map"
+msgstr "Renomear Mapa"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Layer Title:"
+msgstr "Título da Camada:"
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Rename Layer"
+msgstr "Renomear Camada"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&Nova Sessão"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "Iniciar uma nova sessão"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "Abrir sessã&o"
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "Abrir um arquivo de sessão"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&Salvar Sessão"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "Salva esta sessão no arquivo que a abriu"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "S&alvar Sessão como..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "Salvar esta sessão em um novo arquivo"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "Árvore da Sessão"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "Liga/Desliga a janela de análise da árvore de sessão"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "Liga/Desliga a Legenda"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "Conexões com Banco de &Dados..."
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "Sair"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "Concluir trabalho com o Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "Sobre..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "Informações sobre os autores do Thuban, versão e módulos"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "Pro&jeção..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "Definir ou alterar a projeção do mapa"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "&Zoom in"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "Alterar para o modo de mapa 'zoom-in'"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "Zoom &out"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "Alterar para o modo de mapa 'zoom-out'"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "&Pan"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "Alterar para o modo de mapa 'pan'"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "&Identificar"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "Alterar para o modo de mapa 'identificar'"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "Rótu&lo"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "Adicionar/Remover Rótulos"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "Extensão total"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "Zoom para a extensão total do mapa"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "Extensão total da camada"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "Zoom para a extensão total da camada"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "Extensão total da seleção"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "Zoom para extensão total da seleção"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "E&xportar"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "Exportar o mapa para arquivo"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "Imprimir"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "Imprimir o mapa"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "&Renomear..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "Renomear o mapa"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "&Adicionar Camada..."
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "Adicionar uma nova camaada ao mapa"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "&Adicionar Camada de Imagem..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "Adicionar uma nova camada de imagem ao mapa"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "Adicionar uma Camada de Banco de &Dados"
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "Adicionar uma nova camada de banco de dados ao mapa ativo"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "&Remover Camada"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "Remover a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "Especifique a projeção para a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&Duplicar"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "Duplicar a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "Re&nomear ..."
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "Renomear a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "Traze&r para cima"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "Trazer para cima a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "Trazer para baixo"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "Trazer para baixo a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "Exibir"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "Tornar a camada selecionada visível"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "Ocultar"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "Tornar a camada selecionada oculta"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "Exibir Ta&bela"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "Exibir a tabela da camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&Propriedades..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "Editar as propriedades da camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "Fazer ligação com Tabela..."
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "Fazer ligação e anexar uma tabela à camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+#, fuzzy
+msgid "Put selected layer to the top"
+msgstr "Duplicar a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1263
+#, fuzzy
+msgid "&Bottom"
+msgstr "Camada Inferior"
+
+#: ../Thuban/UI/mainwindow.py:1264
+#, fuzzy
+msgid "Put selected layer to the bottom"
+msgstr "Duplicar a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1266
+#, fuzzy
+msgid "&Visible"
+msgstr "Visível"
+
+#: ../Thuban/UI/mainwindow.py:1268
+#, fuzzy
+msgid "Toggle visibility of selected layer"
+msgstr "Trazer para cima a camada selecionada"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "Desfazer ligação de tabela..."
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "Desfazer a última operação de ligação"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "Abrir..."
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "Abrir uma tabela-DBF de um arquivo"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "Fechar..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "Fechar uma ou mais tabela de uma lista"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "Renomear uma ou mais tabelas"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "Exibir"
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "Exibir uma ou mais tabelas em um diálogo"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "Ligação..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "Ligar duas tabelas criando uma nova"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "Arquivo"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&Mapa"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "Camada"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&Tabela"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "Ajuda"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "Submenu %s não existe"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Transversa de Mercator"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Universal Transversa de Mercator"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert Cônica Conforme"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Geográfica"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "Importar..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "Exportar..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "Exibir EPSG:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "Normal"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "Não aprovada"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "Editar"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "Nome:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "Projeção:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<Desconhecida>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "Nova"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "Adicionar à Lista"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "Atualizar"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"Avisos ao ler \"%s\":\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "Importar"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "Avisos"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "Exportar"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "O seguinte erro ocorreu:\n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "Erro"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "Nenhuma Projeção selecionada"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "Fonte da Projeção: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "Múltiplas Projeções selecionadas"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Aérea"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "Elipsóide:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban não reconhece os parâmetros\n"
+"para a atual projeção e não pode\n"
+"exibir um painel de configuração.\n"
+"\n"
+"O conjunto não identificado de parâmetros é:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "Latitude:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "Longitude:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "Falso Leste:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "Falso Norte:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "Fator de Escala:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "Sugestão"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "Hemisfério Sul"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "Zona:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "Impossível sugerir: Retângulo Envolvente não encontrado"
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "Projeção: Sugerir Zona UTM"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "Latitude do primeiro paralelo:"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "Latitude do segundo paralelo:"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "Meridiano Central:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "Latitude de origem:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "Graus"
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "Radianos"
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "Fonte de dados está em:"
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "O centro da extensão corrente do mapa fica na Zona UTM"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "Take"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "Projeções disponíveis"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<Nenhuma>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (atual)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "Retângulo envolvente (lat-lon):"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "Propriedades da Camada"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "Campo: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "Número de Classes:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "Substituir Seleção"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "Refinar Seleção"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "Adicionar à Seleção"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "Pesquisar"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "Exportar Seleção"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "Seleção"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i registros (%i selecionados), %i colunas"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "Exportar Tabela para"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "Arquivos DBF (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "Arquivos CSV (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "Todos arquivos (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "Sessão"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "Exportar Mapa"
+
+#~ msgid "Type: %s"
+#~ msgstr "Tipo: %s"
+
+#~ msgid "Projection: UTM Parameters"
+#~ msgstr "Projeção: Parâmetros UTM"
+
+#~ msgid "UTM Zone"
+#~ msgstr "Zona UTM"
+
+#~ msgid "Ellipsoid"
+#~ msgstr "Elipsóide"
Added: packages/thuban/branches/upstream/current/po/ru.po
===================================================================
--- packages/thuban/branches/upstream/current/po/ru.po 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/ru.po 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1851 @@
+# Russian Translations for Thuban
+# Copyright (C) 2003 Alex Shevlakov
+# This file is distributed under the same license as the PACKAGE package.
+# Alex Shevlakov <alex at motivation.ru>
+msgid ""
+msgstr ""
+"Project-Id-Version: Thuban 0.9.0 CVS\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:15+0000\n"
+"PO-Revision-Date: 2003-12-26 12:00+0400\n"
+"Last-Translator: Alex Shevlakov <alex at motivation.ru>\n"
+"Language-Team: RU\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=koi8-r\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr "%s %s < %s"
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr "ÎÅÔ ÐÒÉÅÍÎÉËÁ ÄÌÑ ËÁÎÁÌÁ %s ÉÚ %s"
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr "ÐÒÉÅÍÎÉË %s%s ÎÅ ÓÏÅÄÉÎÅÎ Ó ËÁÎÁÌÏÍ %s ÉÚ %s"
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr "ðÒÅÄÕÐÒÅÖÄÅÎÉÅ: %s.%s: %s%s\n"
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr "\tÍÅÔÏÄ %s ÉÚ %s"
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr "ÐÅÒ×ÙÍ ÁÒÇÕÍÅÎÔÏÍ ÄÏÌÖÅÎ ÂÙÔØ ÁÂÓÏÌÀÔÎÙÊ ÐÕÔØ Ë ÆÁÊÌÕ"
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr "ïÂÁ ÐÁÒÁÍÅÔÒÁ ÄÏÌÖÎÙ ÉÍÅÔØ ÂÕË×Õ ÎÁÚ×ÁÎÉÑ ÖÅÓÔËÏÇÏ ÄÉÓËÁ"
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr "äÌÑ ÐÌÁÔÆÏÒÍÙ ÎÅ ×ÙÐÏÌÎÅÎ get_application_dir"
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr "äÌÑ ÐÌÁÔÆÏÒÍÙ ÎÅ ×ÙÐÏÌÎÅÎ relative_filename"
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr "ÎÅÐÒÁ×ÉÌØÎÙÊ ÉÎÄÅËÓ"
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr "îÅÔ"
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr "ã×ÅÔ ÌÉÎÉÉ"
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr "ûÉÒÉÎÁ ÌÉÎÉÉ: %s"
+
+#: ../Thuban/Model/classification.py:333
+#, fuzzy, python-format
+msgid "Size: %s"
+msgstr "ðÏÌÅ: %s"
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr "úÁËÒÁÓÉÔØ"
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr "ëÌÁÓÓÉÆÉËÁÃÉÑ"
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr "lineWidth < 1"
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr "ðÏ ÕÍÏÌ."
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr "ôÁÂÌÉÃÁ ÎÅÓÏ×ÍÅÓÔÉÍÁ Ó shapestore"
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr "äÏÐÏÌÎÅÎÉÅ: %s"
+
+#: ../Thuban/Model/label.py:91
+#, fuzzy, python-format
+msgid "Number of labels: %d"
+msgstr "þÉÓÌÏ ËÌÁÓÓÏ×:"
+
+#: ../Thuban/Model/label.py:92
+#, fuzzy, python-format
+msgid "Label Layer: %s"
+msgstr "ôÁÂÌÉÃÁ: "
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr "æÁÊÌ: %s"
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr "ðÏËÁÚÁÎ"
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr "óÐÒÑÔÁÎ"
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr "Shapes: %d"
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr "òÁÚÍÁÈ (ÛÉÒ.-ÄÏÌÇ.): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr "òÁÚÍÁÈ (ÛÉÒ.-ÄÏÌÇ.):"
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr "Shapetype: %s"
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr "ðÒÏÅËÃÉÑ"
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr "óÌÏÊ '%s'"
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr "îÅ×ÅÒÎÁÑ ÛÅÓÔÎÁÄÃÁÔÅÒÉÞÎÁÑ ÓÐÅÃÉÆÉËÁÃÉÑ Ã×ÅÔÁ %s"
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr "îÅ×ÅÒÎÁÑ ÓÐÅÃÉÆÉËÁÃÉÑ Ã×ÅÔÁ %s"
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr "ÔÉÐ ÐÏÌÑ xml ÏÔÌÉÞÁÅÔÓÑ ÏÔ âä! "
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr "äÉÁÐÁÚÏÎ ËÌÁÓÓÉÆÉËÁÃÉÉ ÎÅ Ñ×ÌÑÅÔÓÑ ÞÉÓÌÏÍ!"
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr "íÅÔËÉ"
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr "òÁÚÍÁÈ (× ÐÒÏÅËÃÉÉ): (%g, %g, %g, %g)"
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr "ëÁÒÔÁ: %s"
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr "îÅÉÚ×ÅÓÔÎÁÑ"
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+"îÅÔ ÐÏÄÄÅÒÖËÉ GDAL, Ô.Ë. ÍÏÄÕÌØ '%s' ÎÅÌØÚÑ ÉÍÐÏÒÔÉÒÏ×ÁÔØ. ïÛÉÂËÁ Python: '%"
+"s'"
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ '%s' : %s"
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr "ïÛÉÂËÁ ÐÒÏÅËÃÉÉ '%s': %s"
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr "ôÉÐ ÇÒÕÐÐÙ ÏÔÓÕÔÓÔ×ÕÅÔ × ËÌÁÓÓÉÆÉËÁÃÉÉ"
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr "æÁÊÌ:"
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr "âÙÌ ÉÚÍÅÎÅÎ"
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr "îÅ ÉÚÍÅÎÑÌÓÑ"
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr "óÅÓÓÉÑ: %s"
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr "ÓÅÓÓÉÑ ÂÅÚ ÎÁÚ×."
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr "ËÁÒÔÁ ÂÅÚ ÎÁÚ×."
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr "ï ÐÒÏÇÒÁÍÍÅ Thuban"
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr "æÒÁÎÃÕÚÓËÉÊ"
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr "îÅÍÅÃËÉÊ"
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr "éÔÁÌØÑÎÓËÉÊ"
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr "òÕÓÓËÉÊ"
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr "éÓÐÁÎÓËÉÊ"
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr "- ÎÅÔ"
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr "éÓÐÏÌØÚÕÅÔÓÑ:\n"
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr "óËÏÍÐÉÌÉÒÏ×ÁÎ ÎÁ:\n"
+
+#: ../Thuban/UI/about.py:90
+#, fuzzy
+msgid "Extensions:\n"
+msgstr "äÏÐÏÌÎÅÎÉÅ: %s"
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr "çÌÁ×ÎÙÊ ÒÁÚÒÁÂÏÔÞÉË:\n"
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr "òÁÚÒÁÂÏÔÞÉËÉ:\n"
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr "ðÅÒÅ×ÏÄ:\n"
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr "äÏÐÏÌÎÅÎÉÑ:\n"
+
+#: ../Thuban/UI/about.py:122
+#, fuzzy
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+"÷ÏÐÒÏÓÙ É ËÏÍÍÅÎÔÁÒÉÉ ÐÒÏÓØÂÁ ÐÒÉÓÙÌÁÔØ ÐÏ ÓÌÅÄÕÀÛÉÍ ÁÄÒÅÓÁÍ:\n"
+"\tòÁÚÒÁÂÏÔÞÉË Thuban:\n"
+"\t\t<thuban at intevation.de>\n"
+"\tMail List Thuban:\n"
+"\t\t<thuban-list at intevation.de>"
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+"Thuban: ðÒÏÇÒÁÍÍÁ ÄÌÑ ÒÁÂÏÔÙ Ó ÇÅÏÇÒÁÆÉÞÅÓËÉÍÉ ÄÁÎÎÙÍÉ. \n"
+"\n"
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr "Thuban ÉÍÅÅÔ ÌÉÃÅÎÚÉÀ GNU GPL"
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr "úÁËÒÙÔØ"
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, fuzzy, python-format
+msgid "Select an alternative data file for %s"
+msgstr "÷ÙÂÒÁÔØ ÏÄÉÎ ÉÌÉ ÎÅÓËÏÌØËÏ ÆÁÊÌÏ× Ó ÄÁÎÎÙÍÉ"
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr "Shapefiles (*.shp)"
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr "÷ÓÅ ÆÁÊÌÙ (*.*)"
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr "îÅ×ÏÚÍÏÖÎÏ ÉÍÐÏÒÔÉÒÏ×ÁÔØ ÍÏÄÕÌØ thubanstart\n"
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr "íÏÄÕÌØ thubanstart ÏÔÓÕÔÓÔ×ÕÅÔ\n"
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr "îÅÔ ÄÉÒÅËÔÏÒÉÉ ~/.thuban\n"
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+"çÒÁÆÉÞÅÓËÉÊ ÉÎÔÅÒÆÅÊÓ ÐÏÌØÚÏ×ÁÔÅÌÑ ÎÁ ÏÓÎÏ×Å wxPython ÄÌÑ ÒÁÂÏÔÙ Ó "
+"ÇÅÏÇÒÁÆÉÞÅÓËÉÍÉ ÄÁÎÎÙÍÉ "
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+"äÁÎÎÁÑ ÓÅÓÓÉÑ ÓÏÄÅÒÖÉÔ ÇÒÁÆÉÞÅÓËÉÊ ÆÁÊÌ,\n"
+"ÎÏ ÎÅÔ ÎÅÏÂÈÏÄÉÍÏÊ ÂÉÂÌÉÏÔÅËÉ GDAL."
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr "âÉÂÌÉÏÔÅËÁ ÏÔÓÕÔÓÔ×ÕÅÔ"
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr "ðÁÒÁÍÅÔÒÙ ÓÏÅÄÉÎÅÎÉÑ Ó âä"
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+"ðÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ × ÐÒÏÇÒÁÍÍÅ:\n"
+"%s\n"
+"(ÐÏÖÁÌÕÊÓÔÁ, ÓÏÏÂÝÉÔÅ ÎÁ http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr "ïÄÎÏÒÏÄÎÏÅ ÒÁÓÐÒÅÄÅÌÅÎÉÅ"
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr "õÎÉËÁÌØÎÙÅ ×ÅÌÉÞÉÎÙ"
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr "ë×ÁÎÔÉÌÉ ÉÚ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr "ã×ÅÔÏ×ÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr "óÅÒÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr "ëÒÁÓÎÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr "úÅÌÅÎÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr "çÏÌÕÂÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr "úÅÌÅÎÏ-ËÒÁÓÎÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr "çÏÒÑÞÁÑ/èÏÌÏÄÎÁÑ ÇÁÍÍÁ"
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr "ëÌÁÓÓÉÆÉËÁÃÉÑ"
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr "óÇÅÎÅÒÉÒÏ×ÁÔØ"
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr "ðÏÌÅ: %s"
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr "ôÉÐ ÄÁÎÎÙÈ: %s"
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr "çÅÎÅÒÉÒÏ×ÁÔØ:"
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr "ã×ÅÔÏ×ÁÑ ÓÈÅÍÁ:"
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr "ã×ÅÔ ÌÉÎÉÉ"
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr "éÚÍÅÎÉÔØ"
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+"îÅ×ÏÚÍÏÖÎÏ ÐÏÄÏÂÒÁÔØ ÔÏÞÎÙÅ Ë×ÁÎÔÉÌÉ,\n"
+"ÏÓÎÏ×Ù×ÁÑÓØ ÎÁ ××ÅÄÅÎÎÙÈ ÄÁÎÎÙÈ É ÄÁÎÎÙÈ ÉÚ ÔÁÂÌÉÃÙ.\n"
+"\n"
+"ðÒÉÎÑÔØ Ó ÄÏÐÕÓËÏÍ ÐÏÇÒÅÛÎÏÓÔÉ?"
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr "ðÒÏÂÌÅÍÁ Ó Ë×ÁÎÔÉÌÑÍÉ"
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr "íÉÎ.:"
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr "íÁËÓ.:"
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr "÷ÚÑÔØ ÉÚ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr "þÉÓÌÏ ÇÒÕÐÐ:"
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr "ûÁÇ:"
+
+#: ../Thuban/UI/classgen.py:647
+#, fuzzy
+msgid "Available"
+msgstr "- ÎÅÔ"
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr "óÏÒÔÉÒÏ×ÁÔØ"
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr "ïÂÒÁÔÎÏ"
+
+#: ../Thuban/UI/classgen.py:687
+#, fuzzy
+msgid "Use"
+msgstr "ðÏÌØÚÏ×ÁÔÅÌØ:"
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr "÷ÚÑÔØ ÉÚ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr "ðÒÉÍÅÎÉÔØ × ÄÉÁÐÁÚÏÎÅ"
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr "þÉÓÌÏ ËÌÁÓÓÏ×:"
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr "îÁÞÁÔØ:"
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr "úÁËÏÎÞÉÔØ:"
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr "ûÁÇ"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr "÷ÉÚÕÁÌØÎÏ"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr "óÉÍ×ÏÌ"
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr "÷ÅÌÉÞÉÎÁ"
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr "íÅÔËÁ"
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr "ðÏ ÕÍÏÌÞÁÎÉÀ"
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr "äÉÁÐÁÚÏÎ"
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr "ëÁÒÔÁ"
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr "ôÅËÓÔ"
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr "ãÅÌÏÅ"
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr "äÅÓÑÔÉÞÎÏÅ"
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr "çÅÎÅÒÉÒÏ×ÁÔØ ËÌÁÓÓ"
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr "äÏÂÁ×ÉÔØ"
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr "ðÏÄÎÑÔØ"
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr "ïÐÕÓÔÉÔØ"
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr "òÅÄÁËÔÉÒÏ×ÁÔØ ÓÉÍ×ÏÌ"
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr "õÂÒÁÔØ"
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr "óÔÏÌÂÅÃ: "
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr "ó×ÏÊÓÔ×Á ÓÌÏÑ"
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr "÷ÙÂÒÁÔØ Ó×ÏÊÓÔ×Á"
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr "ðÒÏÓÍÏÔÒ:"
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr "éÚÍÅÎÉÔØ Ã×ÅÔ ÌÉÎÉÉ"
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr "ðÒÏÚÒÁÞÎÁÑ"
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr "éÚÍÅÎÉÔØ Ã×ÅÔ ÚÁËÒÁÓËÉ"
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr "ûÉÒÉÎÁ ÌÉÎÉÉ: "
+
+#: ../Thuban/UI/classifier.py:1242
+#, fuzzy
+msgid "Size: "
+msgstr "îÁÚ×ÁÎÉÅ:"
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr "OK"
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr "ïÔÍÅÎÉÔØ"
+
+#: ../Thuban/UI/colordialog.py:39
+#, fuzzy
+msgid "Select Color"
+msgstr "÷ÙÂÏÒËÁ"
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr "óÔÏÌÂÅÃ"
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr "÷ÙÂÒÁÔØ ÓÌÏÊ ÉÚ ÂÁÚÙ ÄÁÎÎÙÈ"
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr "âÁÚÙ ÄÁÎÎÙÈ"
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr "ðÏÌÕÞÉÔØ"
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr "&ôÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr "éÍÑ ÈÏÓÔÁ:"
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr "ðÏÒÔ:"
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr "îÁÚ×ÁÎÉÅ âä:"
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr "ðÏÌØÚÏ×ÁÔÅÌØ:"
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr "ðÁÒÏÌØ:"
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr "áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ âä"
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr "äÏÂÁ×ÉÔØ âä"
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr "óÏÅÄÉÎÅÎÉÅ Ó '%s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr "úÁËÒÙÔØ ÓÏÅÄÉÎÅÎÉÅ Ó âä"
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+"óÏÅÄÉÎÅÎÉÅ %s\n"
+"ÅÝÅ ÉÓÐÏÌØÚÕÅÔÓÑ"
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr "ïÔËÒÅÐÉÔØ"
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr "ðÒÉËÒÅÐÉÔØ"
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr "Thuban: ×ÎÕÔÒÅÎÎÑÑ ÏÛÉÂËÁ"
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr "ðÒÏÄÏÌÖÉÔØ"
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr "éÎÆÏÒÍÁÃÉÑ Ï ÏÂßÅËÔÅ"
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr "úÁËÒÙÔØ ÏËÎÏ"
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr "îÅ ÐÒÏÉÚ×ÏÄÉÔØ ÚÁÐÒÏÓ"
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr "ðÒÉÓÏÅÄÉÎÉÔØ"
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+#, fuzzy
+msgid "Select..."
+msgstr "÷ÙÂÏÒËÁ"
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr "ôÁÂÌÉÃÁ:"
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr "óÔÏÌÂÅÃ:"
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr "÷ÎÅÛÎÑÑ Ó×ÑÚØ ÔÁÂÌÉà (ÓÏÈÒÁÎÑÅÔ ÏÓÔÁ×ÛÉÅÓÑ ÓÔÒÏËÉ)"
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+"óÂÏÊ Ó×ÑÚÉ:\n"
+" %s"
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr "éÎÆÏ"
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+"ðÒÉÓÏÅÄÉÎÅÎÎÁÑ ÔÁÂÌÉÃÁ ÉÍÅÅÔ %(joined)d ÓÔÒÏË, ÎÏ ÄÏÌÖÎÏ ÂÙÔØ %(needed)d ÄÌÑ "
+"×ÏÚÍÏÖÎÏÓÔÉ ÉÓÐÏÌØÚÏ×ÁÎÉÑ ×ÙÂÒÁÎÎÏÇÏ ÓÌÏÑ"
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr "óÂÏÊ Ó×ÑÚÉ"
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, fuzzy, python-format
+msgid "Table: %s"
+msgstr "ôÁÂÌÉÃÁ: "
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr "úÎÁÞÅÎÉÑ ÍÅÔÏË"
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr "îÁÚ×ÁÎÉÅ:"
+
+#: ../Thuban/UI/layerproperties.py:65
+#, fuzzy, python-format
+msgid "Layer Type: %s"
+msgstr "ôÁÂÌÉÃÁ ÓÌÏÑ: %s"
+
+#: ../Thuban/UI/layerproperties.py:71
+#, fuzzy
+msgid "Projection: None"
+msgstr "ðÒÏÅËÃÉÑ:"
+
+#: ../Thuban/UI/layerproperties.py:73
+#, fuzzy, python-format
+msgid "Projection: %s"
+msgstr "ðÒÏÅËÃÉÑ:"
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr "ðÒÏÂÁ"
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr "÷ÅÒÎÕÔØ"
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr "îÁ ÓÁÍÙÊ ×ÅÒÈ"
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr "ðÏÄÎÑÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr "ïÐÕÓÔÉÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr "÷ ÓÁÍÙÊ ÎÉÚ"
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr "ðÏËÁÚÁÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr "óËÒÙÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr "òÅÄÁËÔÉÒÏ×ÁÔØ Ó×ÏÊÓÔ×Á ÓÌÏÑ"
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, fuzzy, python-format
+msgid "Unknown command %s"
+msgstr "îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ %"
+
+#: ../Thuban/UI/mainwindow.py:299
+#, fuzzy, python-format
+msgid "Unknown command ID %d"
+msgstr "îÅÉÚ×ÅÓÔÎÁÑ ID ËÏÍÁÎÄÙ %"
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr "äÉÁÌÏÇ %s ÕÖÅ ÏÔËÒÙÔ"
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr "÷ÙÊÔÉ"
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr "óÅÓÓÉÑ ÂÙÌÁ ÉÚÍÅÎÅÎÁ. óÏÈÒÁÎÉÔØ?"
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr "ïÔËÒÙÔØ"
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr "óÏÈÒÁÎÉÔØ ËÁË"
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr "÷ÙÂÒÁÔØ ÏÄÉÎ ÉÌÉ ÎÅÓËÏÌØËÏ ÆÁÊÌÏ× Ó ÄÁÎÎÙÍÉ"
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr "äÏÂÁ×ÉÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, fuzzy, python-format
+msgid "Can't open the file '%s'."
+msgstr "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ '%'"
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr "÷ÙÂÒÁÔØ ÇÒÁÆÉÞÅÓËÉÊ ÆÁÊÌ"
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr "äÏÂÁ×ÉÔØ ÒÁÓÔÒ"
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr "äÏÂÁ×ÉÔØ ÓÌÏÊ ÉÚ âä"
+
+#: ../Thuban/UI/mainwindow.py:630
+#, fuzzy, python-format
+msgid "Can't open the database table '%s'"
+msgstr "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ âä '%'."
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr "ëÏÐÉÑ `%s'"
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr "ôÁÂÌÉÃÁ ÓÌÏÑ: %s"
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr "ðÒÏÅËÃÉÑ ËÁÒÔÙ: %s"
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr "ðÒÏÅËÃÉÑ ÓÌÏÑ: %s"
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr "óÏÅÄÉÎÉÔØ ÓÌÏÊ Ó ÔÁÂÌÉÃÅÊ"
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr "õÓÌÏ×ÎÙÅ ÏÂÏÚÎÁÞÅÎÉÑ"
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr "ïÔËÒÙÔØ ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr "æÁÊÌÙ DBF (*.dbf) "
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr "÷ÙÂÒÁÔØ ÔÁÂÌÉÃÕ:"
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr "úÁËÒÙÔØ ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr "÷ÙÂÒÁÔØ ÔÁÂÌÉÃÕ:"
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr "ðÏËÁÚÁÔØ ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr "ðÒÉÓÏÅÄÉÎÉÔØ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr "÷ÙÂÒÁÔØ ÔÁÂÌÉÃÕ:"
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:942
+#, fuzzy
+msgid "Table Title:"
+msgstr "ôÁÂÌÉÃÁ:"
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Map Title:"
+msgstr "îÁÚ×ÁÎÉÅ:"
+
+#: ../Thuban/UI/mainwindow.py:991
+#, fuzzy
+msgid "Rename Map"
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ ËÁÒÔÕ"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Layer Title:"
+msgstr "ôÁÂÌÉÃÁ ÓÌÏÑ: %s"
+
+#: ../Thuban/UI/mainwindow.py:1004
+#, fuzzy
+msgid "Rename Layer"
+msgstr "&õÂÒÁÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr "Thuban - %s"
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr "Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr "&îÏ×ÁÑ ÓÅÓÓÉÑ"
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr "îÁÞÁÔØ ÎÏ×ÕÀ ÓÅÓÓÉÀ"
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr "&ïÔËÒÙÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr "ïÔËÒÙÔØ ÆÁÊÌ ÓÅÓÓÉÉ"
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr "&óÏÈÒÁÎÉÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr "óÏÈÒÁÎÉÔØ ÓÅÓÓÉÀ × ÆÁÊÌ"
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr "óÏÈÒÁÎÉÔØ ËÁË..."
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr "óÏÈÒÁÎÉÔØ × ÎÏ×ÙÊ ÆÁÊÌ"
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr "äÅÒÅ×Ï ÓÅÓÓÉÉ"
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr "ðÏËÁÚÁÔØ/õÂÒÁÔØ ÄÅÒÅ×Ï ÓÅÓÓÉÉ"
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr "ðÏËÁÚÁÔØ/õÂÒÁÔØ ÕÓÌÏ×ÎÙÅ ÏÂÏÚÎÁÞÅÎÉÑ"
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr "&ó×ÑÚØ Ó âä"
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr "&÷ÙÊÔÉ"
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr "úÁËÏÎÞÉÔØ ÒÁÂÏÔÕ Ó ÐÒÏÇÒÁÍÍÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr "&ï ÐÒÏÇÒÁÍÍÅ..."
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr "éÎÆÏÒÍÁÃÉÑ Ï Á×ÔÏÒÁÈ, ×ÅÒÓÉÉ É ÍÏÄÕÌÑÈ Thuban"
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr "&ðÒÏÅËÃÉÑ..."
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr "õÓÔÁÎÏ×ÉÔØ ÉÌÉ ÐÏÍÅÎÑÔØ ÐÒÏÅËÃÉÀ ËÁÒÔÙ"
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr "õ×ÅÌÉÞÉÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr "òÅÖÉÍ Õ×ÅÌÉÞÅÎÉÑ"
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr "õÍÅÎØÛÉÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr "òÅÖÉÍ ÕÍÅÎØÛÅÎÉÑ"
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr "&ðÅÒÅÎÏÓ"
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr "òÅÖÉÍ ÐÅÒÅÎÏÓÁ ÐÏ ËÁÒÔÅ"
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr "úÁÐÒÏÓ"
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr "òÅÖÉÍ ÚÁÐÒÏÓÏ×"
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr "íÅÔËÉ"
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr "äÏÂÁ×ÉÔØ/õÂÒÁÔØ ÍÅÔËÉ"
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr "÷ÅÓØ ÒÁÊÏÎ"
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr "õÓÔÁÎÏ×ÉÔØ ÏËÎÏ ÐÏ ×ÓÅÍÕ ÒÅÇÉÏÎÕ"
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr "÷ÅÓØ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr "õÓÔÁÎÏ×ÉÔØ ÏËÎÏ ÐÏ ×ÓÅÍÕ ÓÌÏÀ"
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr "÷ÓÑ ×ÙÂÏÒËÁ"
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr "õÓÔÁÎÏ×ÉÔØ ÏËÎÏ ÐÏ ×ÓÅÊ ×ÙÂÏÒËÅ"
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr "üËÓÐÏÒÔ"
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr "üËÓÐÏÒÔÉÒÏ×ÁÔØ ËÁÒÔÕ × ÆÁÊÌ"
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr "ðÅÞÁÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr "îÁÐÅÞÁÔÁÔØ ËÁÒÔÕ"
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ ËÁÒÔÕ"
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr "&îÏ×ÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr "äÏÂÁ×ÉÔØ ÓÌÏÊ Ë ËÁÒÔÅ"
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr "&äÏÂÁ×ÉÔØ ÒÁÓÔÒ..."
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr "äÏÂÁ×ÉÔØ ÒÁÓÔÒÏ×ÏÅ ÉÚÏÂÒÁÖÅÎÉÅ × ËÁÒÔÕ"
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr "&äÏÂÁ×ÉÔØ ÓÌÏÊ âä"
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr "äÏÂÁ×ÉÔØ ÎÏ×ÙÊ ÓÌÏÊ âä"
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr "&õÂÒÁÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr "õÂÒÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr "õËÁÚÁÔØ ÐÒÏÅËÃÉÀ ÄÌÑ ×ÙÂÒÁÎÎÏÇÏ ÓÌÏÑ"
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr "&äÏÂÁ×ÉÔØ ËÏÐÉÀ"
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr "óËÏÐÉÒÏ×ÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr "ðÏÄÎÑÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr "ðÏÄÎÑÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr "ïÐÕÓÔÉÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr "ïÐÕÓÔÉÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr "&ðÏËÁÚÁÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr "ðÏËÁÚÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr "&óÐÒÑÔÁÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr "îÅ ÐÏËÁÚÙ×ÁÔØ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr "ðÏËÁÚÁÔØ &ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr "ðÏËÁÚÁÔØ ÔÁÂÌÉÃÕ ÄÌÑ ÌÁÎÎÏÇÏ ÓÌÏÑ"
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr "&ó×ÏÊÓÔ×Á..."
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr "òÅÄÁËÔÉÒÏ×ÁÔØ Ó×ÏÊÓÔ×Á ÄÁÎÎÏÇÏ ÓÌÏÑ"
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr "&ðÒÉÓÏÅÄÉÎÉÔØ ÔÁÂÌÉÃÕ"
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr "ðÒÉËÒÅÐÉÔØ ÔÁÂÌÉÃÕ Ë ÄÁÎÎÏÇÏ ÓÌÏÀ"
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+#, fuzzy
+msgid "Put selected layer to the top"
+msgstr "óËÏÐÉÒÏ×ÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1263
+#, fuzzy
+msgid "&Bottom"
+msgstr "÷ ÓÁÍÙÊ ÎÉÚ"
+
+#: ../Thuban/UI/mainwindow.py:1264
+#, fuzzy
+msgid "Put selected layer to the bottom"
+msgstr "óËÏÐÉÒÏ×ÁÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1266
+#, fuzzy
+msgid "&Visible"
+msgstr "÷ÉÚÕÁÌØÎÏ"
+
+#: ../Thuban/UI/mainwindow.py:1268
+#, fuzzy
+msgid "Toggle visibility of selected layer"
+msgstr "ðÏÄÎÑÔØ ×ÙÂÒÁÎÎÙÊ ÓÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr "ïÔÓÏÅÄÉÎÉÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr "ïÔÍÅÎÉÔØ ÐÏÓÌÅÄÎÀÀ ÏÐÅÒÁÃÉÀ ÐÒÉÓÏÅÄÉÎÅÎÉÑ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr "&ïÔËÒÙÔØ"
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr "ïÔËÒÙÔØ DBF-ÔÁÂÌÉÃÕ ÉÚ ÆÁÊÌÁ"
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr "&úÁËÒÙÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr "úÁËÒÙÔØ ÏÄÎÕ ÉÌÉ ÎÅÓËÏÌØËÏ ÔÁÂÌÉÃ ÉÚ ÓÐÉÓËÁ"
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr "ðÅÒÅÉÍÅÎÏ×ÁÔØ ÏÄÎÕ ÉÌÉ ÎÅÓËÏÌØËÏ ÔÁÂÌÉÃ"
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr "&ðÏËÁÚÁÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr "ðÏËÁÚÁÔØ × ÏËÎÅ ÏÄÎÕ ÉÌÉ ÎÅÓËÏÌØËÏ ÔÁÂÌÉÃ"
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr "&ðÒÉÓÏÅÄÉÎÉÔØ..."
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr "óÏÅÄÉÎÉÔØ Ä×Å ÔÁÂÌÉÃÙ × ÏÄÎÕ"
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr "&æÁÊÌ"
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr "&ëÁÒÔÁ"
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr "&óÌÏÊ"
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr "&ôÁÂÌÉÃÁ"
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr "&ðÏÍÏÝØ"
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr "íÅÎÀ %s ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr "Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr "Universal Transverse Mercator"
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr "Lambert Conic Conformal"
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr "Geographic"
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr "éÍÐÏÒÔ..."
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr "üËÓÐÏÒÔ..."
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr "ðÏËÁÚÁÔØ EPSG:"
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr "îÏÒÍÁÌØÎÙÊ"
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr "îÅ ÉÓÐÏÌØÚÕÅÔÓÑ"
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr "òÅÄÁËÔÉÒÏ×ÁÔØ"
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr "îÁÚ×ÁÎÉÅ:"
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr "ðÒÏÅËÃÉÑ:"
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr "<îÅÉÚ×ÅÓÔÎÁÑ>"
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr "îÏ×ÁÑ"
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr "äÏÂÁ×ÉÔØ × ÓÐÉÓÏË"
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr "éÚÍÅÎÉÔØ"
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+"ðÒÅÄÕÐÒÅÖÄÅÎÉÅ '%s':\n"
+"\n"
+"%s"
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr "éÍÐÏÒÔ"
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr "ðÒÅÄÕÐÒÅÖÄÅÎÉÑ"
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr "üËÓÐÏÒÔ"
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr "ðÒÏÉÚÏÛÌÁ ÓÌÅÄÕÀÝÁÑ ÏÛÉÂËÁ: \n"
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr "ïÛÉÂËÁ"
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr "ðÒÏÅËÃÉÑ ÎÅ ÕÓÔÁÎÏ×ÌÅÎÁ"
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr "éÓÈÏÄÎÁÑ ÐÒÏÅËÃÉÑ: %s"
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr "÷ÙÂÒÁÎÏ ÍÎÏÇÏ ÐÒÏÅËÃÉÊ"
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr "Airy"
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr "Bessel 1841"
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr "Clarke 1866"
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr "Clarke 1880"
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr "GRS 1980 (IUGG, 1980)"
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr "International 1909 (Hayford)"
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr "WGS 84"
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr "üÌÌÉÐÓÏÉÄ:"
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+"Thuban ÎÅ ÚÎÁÅÔ ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÄÁÎÎÏÊ ÐÒÏÅËÃÉÉ\n"
+"É ÎÅ ÍÏÖÅÔ ÐÏËÁÚÁÔØ\n"
+"ÐÁÎÅÌØ \n"
+"ËÏÎÆÉÇÕÒÁÃÉÉ.\n"
+"\n"
+"îÅÉÚ×ÅÓÔÎÙÊ ÎÁÂÏÒ ÐÁÒÁÍÅÔÒÏ×:\n"
+"\n"
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr "ûÉÒÏÔÁ:"
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr "äÏÌÇÏÔÁ:"
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr "÷ÏÓÔÏÞÎÏÅ ÏÔËÌÏÎÅÎÉÅ:"
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr "óÅ×ÅÒÎÏÅ ÏÔËÌÏÎÅÎÉÅ:"
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr "íÁÓÛÔÁÂÎÙÊ ÍÎÏÖÉÔÅÌØ:"
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr "õÓÔÁÎÏ×ÉÔØ"
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr "àÖÎÏÅ ÐÏÌÕÛÁÒÉÅ"
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr "úÏÎÁ:"
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr "îÅ×ÏÚÍÏÖÎÏ ÐÒÅÄÌÏÖÉÔØ: ÎÅ ÎÁÊÄÅÎ Bounding Box."
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr "ðÒÏÅËÃÉÑ: ÕÓÔÁÎÏ×ÉÔØ ÚÏÎÕ UTM"
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr "ûÉÒÏÔÁ ÐÅÒ×ÏÊ ÓÔÁÎÄÁÒÔÎÏÊ ÐÁÒÁÌÌÅÌÉ"
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr "ûÉÒÏÔÁ ×ÔÏÒÏÊ ÓÔÁÎÄÁÒÔÎÏÊ ÐÁÒÁÌÌÅÌÉ"
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr "ãÅÎÔÒÁÌØÎÙÊ ÍÅÒÉÄÉÁÎ:"
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr "ïÓÎÏ×ÎÁÑ ÛÉÒÏÔÁ:"
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr "çÒÁÄ."
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr "òÁÄ."
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr "éÓÈÏÄÎÙÅ ÄÁÎÎÙÅ ×: "
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr "ãÅÎÔÒ ÒÁÓÐÏÌÏÖÅÎÉÑ ÄÁÎÎÏÊ ËÁÒÔÙ ÎÁÈÏÄÉÔÓÑ × UTM Zone"
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr "ðÒÉÎÑÔØ"
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr "÷ÏÚÍÏÖÎÙÅ ÐÒÏÅËÃÉÉ:"
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr "<îÅÔ>"
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr "%s (ÔÅËÕÝ.)"
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+#, fuzzy
+msgid "Extent (lat-lon): None"
+msgstr "òÁÚÍÁÈ (ÛÉÒ.-ÄÏÌÇ.):"
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+#, fuzzy
+msgid "Image Properties"
+msgstr "ó×ÏÊÓÔ×Á ÓÌÏÑ"
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, fuzzy, python-format
+msgid "Driver: %s"
+msgstr "ðÏÌÅ: %s"
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, fuzzy, python-format
+msgid "Number of Bands: %i"
+msgstr "þÉÓÌÏ ËÌÁÓÓÏ×:"
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr "îÏ×ÁÑ ×ÙÂÏÒËÁ"
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr "õÔÏÞÎÉÔØ ×ÙÂÏÒËÕ"
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr "äÏÂÁ×ÉÔØ × ×ÙÂÏÒËÕ"
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr "úÁÐÒÏÓ"
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr "üËÓÐÏÒÔ ×ÙÂÏÒËÉ"
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr "÷ÙÂÏÒËÁ"
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr "%i ÓÔÒÏË (%i ×ÙÂÒÁÎÏ), %i ÓÔÏÌÂÃÏ×"
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr "üËÓÐÏÒÔ ÔÁÂÌÉÃÙ"
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr "æÁÊÌÙ DBF (*.dbf)|*.dbf|"
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr "æÁÊÌÙ CSV (*.csv)|*.csv|"
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr "÷ÓÅ ÆÁÊÌÙ (*.*)|*.*"
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr "óÅÓÓÉÑ"
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr "üËÓÐÏÒÔ ËÁÒÔÙ"
+
+#~ msgid "Type: %s"
+#~ msgstr "ôÉÐ: %s"
+
+#~ msgid "Projection: UTM Parameters"
+#~ msgstr "ðÒÏÅËÃÉÑ: ÐÁÒÁÍÅÔÒÙ UTM"
+
+#~ msgid "UTM Zone"
+#~ msgstr "úÏÎÁ UTM"
+
+#~ msgid "Ellipsoid"
+#~ msgstr "üÌÌÉÐÓÏÉÄ"
Added: packages/thuban/branches/upstream/current/po/thuban.pot
===================================================================
--- packages/thuban/branches/upstream/current/po/thuban.pot 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/po/thuban.pot 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1783 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-03-13 20:29+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../Thuban/version.py:189
+#, python-format
+msgid "%s %s < %s"
+msgstr ""
+
+#: ../Thuban/version.py:195
+#, python-format
+msgid "Thuban was compiled with wx %(wxproj-wx)s but wxPython is %(wxPython)s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:65
+#, python-format
+msgid "no receivers for channel %s of %s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:70
+#, python-format
+msgid "receiver %s%s is not connected to channel %s of %s"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:94
+#, python-format
+msgid "Warning: %s.%s: %s%s\n"
+msgstr ""
+
+#: ../Thuban/Lib/connector.py:118
+#, python-format
+msgid "\tmethod %s of %s"
+msgstr ""
+
+#: ../Thuban/Lib/fileutil.py:87 ../Thuban/Lib/fileutil.py:141
+msgid "first argument must be an absolute filename"
+msgstr ""
+
+#: ../Thuban/Lib/fileutil.py:138
+msgid "Both parameters must have a drive letter"
+msgstr ""
+
+#: ../Thuban/Lib/fileutil.py:198
+msgid "No implementation of get_application_dir available for platform"
+msgstr ""
+
+#: ../Thuban/Lib/fileutil.py:208
+msgid "No implementation of relative_filename available for platform"
+msgstr ""
+
+#: ../Thuban/Model/classgen.py:338
+msgid "invalid index"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:309 ../Thuban/UI/classifier.py:758
+msgid "None"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:325
+msgid "Line Color"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:327
+#, python-format
+msgid "Line Width: %s"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:333
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:336
+msgid "Fill"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:342 ../Thuban/UI/classifier.py:841
+msgid "Classification"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:436
+msgid "lineWidth < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:451
+msgid "size < 1"
+msgstr ""
+
+#: ../Thuban/Model/classification.py:656 ../Thuban/UI/classifier.py:528
+msgid "DEFAULT"
+msgstr ""
+
+#: ../Thuban/Model/data.py:316
+msgid "Table not compatible with shapestore."
+msgstr ""
+
+#: ../Thuban/Model/extension.py:90
+#, python-format
+msgid "Extension: %s"
+msgstr ""
+
+#: ../Thuban/Model/label.py:91
+#, python-format
+msgid "Number of labels: %d"
+msgstr ""
+
+#: ../Thuban/Model/label.py:92
+#, python-format
+msgid "Label Layer: %s"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:298 ../Thuban/Model/layer.py:566
+#: ../Thuban/Model/session.py:432
+#, python-format
+msgid "Filename: %s"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:301 ../Thuban/Model/layer.py:569
+msgid "Shown"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:303 ../Thuban/Model/layer.py:571
+msgid "Hidden"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:304
+#, python-format
+msgid "Shapes: %d"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:308 ../Thuban/Model/layer.py:575
+#: ../Thuban/Model/map.py:287 ../Thuban/UI/rasterlayerproperties.py:51
+#, python-format
+msgid "Extent (lat-lon): (%g, %g, %g, %g)"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:310 ../Thuban/Model/layer.py:577
+msgid "Extent (lat-lon):"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:311
+#, python-format
+msgid "Shapetype: %s"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:314 ../Thuban/Model/layer.py:580
+#: ../Thuban/Model/map.py:292
+msgid "Projection"
+msgstr ""
+
+#: ../Thuban/Model/layer.py:319 ../Thuban/Model/layer.py:583
+#, python-format
+msgid "Layer '%s'"
+msgstr ""
+
+#: ../Thuban/Model/load.py:78
+#, python-format
+msgid "Invalid hexadecimal color specification %s"
+msgstr ""
+
+#: ../Thuban/Model/load.py:81
+#, python-format
+msgid "Invalid color specification %s"
+msgstr ""
+
+#: ../Thuban/Model/load.py:544
+msgid "xml field type differs from database!"
+msgstr ""
+
+#: ../Thuban/Model/load.py:609
+msgid "Classification range is not a number!"
+msgstr ""
+
+#: ../Thuban/Model/map.py:53
+msgid "Labels"
+msgstr ""
+
+#: ../Thuban/Model/map.py:290
+#, python-format
+msgid "Extent (projected): (%g, %g, %g, %g)"
+msgstr ""
+
+#: ../Thuban/Model/map.py:301
+#, python-format
+msgid "Map: %s"
+msgstr ""
+
+#: ../Thuban/Model/proj.py:84 ../Thuban/Model/resource.py:179
+msgid "Unknown"
+msgstr ""
+
+#: ../Thuban/Model/resource.py:46
+#, python-format
+msgid ""
+"No GDAL support because module '%s' cannot be imported. Python exception: '%"
+"s'"
+msgstr ""
+
+#: ../Thuban/Model/resource.py:135 ../Thuban/Model/resource.py:155
+#, python-format
+msgid "Could not read \"%s\": %s"
+msgstr ""
+
+#: ../Thuban/Model/resource.py:187
+#, python-format
+msgid "Error in projection \"%s\": %s"
+msgstr ""
+
+#: ../Thuban/Model/save.py:352
+msgid "Unsupported group type in classification"
+msgstr ""
+
+#: ../Thuban/Model/session.py:430
+msgid "Filename:"
+msgstr ""
+
+#: ../Thuban/Model/session.py:435
+msgid "Modified"
+msgstr ""
+
+#: ../Thuban/Model/session.py:437
+msgid "Unmodified"
+msgstr ""
+
+#: ../Thuban/Model/session.py:442
+#, python-format
+msgid "Session: %s"
+msgstr ""
+
+#: ../Thuban/Model/session.py:448
+msgid "unnamed session"
+msgstr ""
+
+#: ../Thuban/Model/session.py:450
+msgid "unnamed map"
+msgstr ""
+
+#: ../Thuban/UI/about.py:28
+msgid "About Thuban"
+msgstr ""
+
+#: ../Thuban/UI/about.py:47
+msgid "French"
+msgstr ""
+
+#: ../Thuban/UI/about.py:48
+msgid "German"
+msgstr ""
+
+#: ../Thuban/UI/about.py:50
+msgid "Hungarian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:51
+msgid "Italian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:52
+msgid "Portuguese (Brazilian)"
+msgstr ""
+
+#: ../Thuban/UI/about.py:53
+msgid "Russian"
+msgstr ""
+
+#: ../Thuban/UI/about.py:54
+msgid "Spanish"
+msgstr ""
+
+#: ../Thuban/UI/about.py:63 ../Thuban/UI/about.py:65 ../Thuban/UI/about.py:67
+msgid "- not available"
+msgstr ""
+
+#: ../Thuban/UI/about.py:72
+msgid "Currently using:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:78
+#, python-format
+msgid "\tInternal encoding: %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:84
+msgid "Compiled for:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:90
+msgid "Extensions:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:95 ../Thuban/UI/about.py:144
+msgid "\tNone registered.\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:98
+msgid "Maintainers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:103
+msgid "Lead Developer:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:106
+msgid "Developers:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:111
+msgid "Translators:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:116
+msgid "Other Contributors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:122
+msgid ""
+"Questions and comments can be sent to the following addresses:\n"
+"\tGeneral list (public):\n"
+"\t\t<thuban-list at intevation.de>\n"
+"\tDevelopers list (public):\n"
+"\t\t<thuban-devel at intevation.de>\n"
+"\tThuban team at Intevation:\n"
+"\t\t<thuban at intevation.de>\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:130
+msgid ""
+"Details on the registered extensions:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:135
+#, python-format
+msgid "Copyright %s\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:136
+msgid "Authors:\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:149
+msgid ""
+"Thuban is a program for exploring geographic data.\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/about.py:151
+msgid "Thuban is licensed under the GNU GPL"
+msgstr ""
+
+#: ../Thuban/UI/about.py:160 ../Thuban/UI/classgen.py:91
+#: ../Thuban/UI/dbdialog.py:276 ../Thuban/UI/dock.py:371
+#: ../Thuban/UI/join.py:66 ../Thuban/UI/layerproperties.py:82
+#: ../Thuban/UI/projdialog.py:209 ../Thuban/UI/tableview.py:388
+msgid "Close"
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:24
+#, python-format
+msgid "Select an alternative data file for %s"
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:31 ../Thuban/UI/mainwindow.py:563
+msgid "Shapefiles (*.shp)"
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:32 ../Thuban/UI/mainwindow.py:564
+#: ../Thuban/UI/mainwindow.py:852
+msgid "All Files (*.*)"
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:47
+#, python-format
+msgid ""
+"Found the following as an alternative for %s.\n"
+"%s\n"
+"\n"
+" Please confirm with Yes or select alternative with No."
+msgstr ""
+
+#: ../Thuban/UI/altpathdialog.py:49
+msgid "Alternative Path"
+msgstr ""
+
+#: ../Thuban/UI/application.py:110 ../Thuban/UI/application.py:122
+msgid "Cannot import the thubanstart module\n"
+msgstr ""
+
+#: ../Thuban/UI/application.py:115
+msgid "No thubanstart module available\n"
+msgstr ""
+
+#: ../Thuban/UI/application.py:126
+msgid "No ~/.thuban directory\n"
+msgstr ""
+
+#: ../Thuban/UI/application.py:166
+msgid ""
+"This is the wxPython-based Graphical User Interface for exploring geographic "
+"data"
+msgstr ""
+
+#: ../Thuban/UI/application.py:254
+msgid ""
+"The current session contains Image layers,\n"
+"but the GDAL library is not available to draw them."
+msgstr ""
+
+#: ../Thuban/UI/application.py:259
+msgid "Library not available"
+msgstr ""
+
+#: ../Thuban/UI/application.py:268 ../Thuban/UI/mainwindow.py:476
+msgid "DB Connection Parameters"
+msgstr ""
+
+#: ../Thuban/UI/application.py:364
+#, python-format
+msgid ""
+"An unhandled exception occurred:\n"
+"%s\n"
+"(please report to http://thuban.intevation.org/bugtracker.html)\n"
+"\n"
+"%s"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:43
+msgid "Uniform Distribution"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:44
+msgid "Unique Values"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:45
+msgid "Quantiles from Table"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:47
+msgid "Custom Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:48
+msgid "Grey Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:49
+msgid "Red Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:50
+msgid "Green Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:51
+msgid "Blue Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:52
+msgid "Green-to-Red Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:53
+msgid "Hot-to-Cold Ramp"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:69
+msgid "Generate Classification"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:90
+msgid "Generate"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:119
+#, python-format
+msgid "Field: %s"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:123 ../Thuban/UI/classifier.py:976
+#, python-format
+msgid "Data Type: %s"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:127
+msgid "Generate:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:137
+msgid "Color Scheme:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:161
+msgid "Fix Border Color"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:168 ../Thuban/UI/classgen.py:936
+#: ../Thuban/UI/classgen.py:967
+msgid "Change"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:274
+msgid ""
+"Based on the data from the table and the input\n"
+"values, the exact quantiles could not be generated.\n"
+"\n"
+"Accept a close estimate?"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:277
+msgid "Problem with Quantiles"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:370
+msgid "Min:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:375
+msgid "Max:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:380 ../Thuban/UI/classgen.py:633
+msgid "Retrieve From Table"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:390
+msgid "Number of Groups:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:397
+msgid "Stepping:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:647
+msgid "Available"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:652 ../Thuban/UI/classgen.py:692
+msgid "Sort"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:655 ../Thuban/UI/classgen.py:695
+msgid "Reverse"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:687
+msgid "Use"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:832
+msgid "Retrieve from Table"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:840
+msgid "Apply to Range"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:847
+msgid "Number of Classes:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:930
+msgid "Start:"
+msgstr ""
+
+#: ../Thuban/UI/classgen.py:961
+msgid "End:"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:164
+msgid "The Default group cannot be removed."
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:309
+#: ../Thuban/UI/classifier.py:467
+msgid "Pattern"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:272 ../Thuban/UI/classifier.py:306
+#: ../Thuban/UI/classifier.py:466
+msgid "Singleton"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Visible"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Symbol"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:317 ../Thuban/UI/controls.py:33
+#: ../Thuban/UI/controls.py:177
+msgid "Value"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:317
+msgid "Label"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:462 ../Thuban/UI/classifier.py:465
+msgid "Default"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:468
+msgid "Range"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:469
+msgid "Map"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:759
+msgid "Text"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:760
+msgid "Integer"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:761
+msgid "Decimal"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:820
+msgid "Generate Class"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:822 ../Thuban/UI/dbdialog.py:274
+msgid "Add"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:824
+msgid "Move Up"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:826
+msgid "Move Down"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:828
+msgid "Edit Symbol"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:830 ../Thuban/UI/dbdialog.py:275
+#: ../Thuban/UI/projdialog.py:117
+msgid "Remove"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:845
+msgid "Field: "
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1000 ../Thuban/UI/layerproperties.py:160
+msgid "Layer Properties"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1167
+msgid "Select Properties"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1178
+msgid "Preview:"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1195
+msgid "Change Line Color"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1201 ../Thuban/UI/classifier.py:1216
+msgid "Transparent"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1212
+msgid "Change Fill Color"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1225
+msgid "Line Width: "
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1242
+msgid "Size: "
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1262 ../Thuban/UI/colordialog.py:52
+#: ../Thuban/UI/dbdialog.py:107 ../Thuban/UI/dbdialog.py:221
+#: ../Thuban/UI/labeldialog.py:41 ../Thuban/UI/layerproperties.py:81
+#: ../Thuban/UI/projdialog.py:205
+msgid "OK"
+msgstr ""
+
+#: ../Thuban/UI/classifier.py:1264 ../Thuban/UI/colordialog.py:53
+#: ../Thuban/UI/dbdialog.py:110 ../Thuban/UI/dbdialog.py:223
+#: ../Thuban/UI/labeldialog.py:42 ../Thuban/UI/projdialog.py:1033
+msgid "Cancel"
+msgstr ""
+
+#: ../Thuban/UI/colordialog.py:39
+msgid "Select Color"
+msgstr ""
+
+#: ../Thuban/UI/controls.py:31
+msgid "Field"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:41
+msgid "Choose layer from database"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:59
+msgid "Databases"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:74
+msgid "Retrieve"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:82
+msgid "Tables"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:92
+msgid "ID Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:98
+msgid "Geometry Column"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:187
+msgid "Hostname:"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:191
+msgid "Port:"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:198
+msgid "Database Name:"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:206
+msgid "User:"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:211
+msgid "Password:"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:286
+msgid "Database Management"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:361 ../Thuban/UI/dbdialog.py:366
+msgid "Add Database"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:367
+#, python-format
+msgid "Connection '%s' already exists"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:388
+msgid "Remove Database Connection"
+msgstr ""
+
+#: ../Thuban/UI/dbdialog.py:389
+#, python-format
+msgid ""
+"The connection %s\n"
+"is still in use"
+msgstr ""
+
+#: ../Thuban/UI/dock.py:190
+msgid "Undock"
+msgstr ""
+
+#: ../Thuban/UI/dock.py:218
+msgid "Dock"
+msgstr ""
+
+#: ../Thuban/UI/exceptiondialog.py:23 ../Thuban/UI/exceptiondialog.py:61
+msgid "Thuban: Internal Error"
+msgstr ""
+
+#: ../Thuban/UI/exceptiondialog.py:43
+msgid "Proceed"
+msgstr ""
+
+#: ../Thuban/UI/exceptiondialog.py:44
+msgid "Exit Thuban now"
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:72
+msgid "Initialization not yet requested."
+msgstr ""
+
+#: ../Thuban/UI/extensionregistry.py:88
+msgid "Initialization successful."
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:44
+msgid "Identify Shape"
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:56
+msgid "Close Window"
+msgstr ""
+
+#: ../Thuban/UI/identifyview.py:57
+msgid "Stop Identify Mode"
+msgstr ""
+
+#: ../Thuban/UI/join.py:64
+msgid "Join"
+msgstr ""
+
+#: ../Thuban/UI/join.py:71 ../Thuban/UI/join.py:72
+msgid "Select..."
+msgstr ""
+
+#: ../Thuban/UI/join.py:100 ../Thuban/UI/join.py:108
+msgid "Table:"
+msgstr ""
+
+#: ../Thuban/UI/join.py:111 ../Thuban/UI/join.py:114
+msgid "Field:"
+msgstr ""
+
+#: ../Thuban/UI/join.py:125
+msgid "Outer Join (preserves left table records)"
+msgstr ""
+
+#: ../Thuban/UI/join.py:173
+#, python-format
+msgid ""
+"Join failed:\n"
+" %s"
+msgstr ""
+
+#: ../Thuban/UI/join.py:174
+msgid "Info"
+msgstr ""
+
+#: ../Thuban/UI/join.py:195
+#, python-format
+msgid ""
+"The joined table has %(joined)d rows but it must have %(needed)d rows to be "
+"used with the selected layer"
+msgstr ""
+
+#: ../Thuban/UI/join.py:200
+msgid "Join Failed"
+msgstr ""
+
+#: ../Thuban/UI/join.py:209 ../Thuban/UI/mainwindow.py:915
+#, python-format
+msgid "Table: %s"
+msgstr ""
+
+#: ../Thuban/UI/labeldialog.py:26
+msgid "Label Values"
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:54
+msgid "Title: "
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:65
+#, python-format
+msgid "Layer Type: %s"
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:71
+msgid "Projection: None"
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:73
+#, python-format
+msgid "Projection: %s"
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:79 ../Thuban/UI/projdialog.py:199
+msgid "Try"
+msgstr ""
+
+#: ../Thuban/UI/layerproperties.py:80 ../Thuban/UI/projdialog.py:202
+msgid "Revert"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:75
+msgid "Top Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:79
+msgid "Raise Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:83
+msgid "Lower Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:87
+msgid "Bottom Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:91
+msgid "Show Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:95
+msgid "Hide Layer"
+msgstr ""
+
+#: ../Thuban/UI/legend.py:99
+msgid "Edit Layer Properties"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:264 ../Thuban/UI/mainwindow.py:286
+#, python-format
+msgid "Unknown command %s"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:299
+#, python-format
+msgid "Unknown command ID %d"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:338
+#, python-format
+msgid "The Dialog named %s is already open"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:396
+#, python-format
+msgid "Select layer '%s' and pick a projection using Layer/Projection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:449
+msgid "Exit"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:450
+msgid "The session has been modified. Do you want to save it?"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:465
+msgid "Open Session"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:487
+msgid "Save Session As"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:561
+msgid "Select one or more data files"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:576
+msgid "Add Layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:577 ../Thuban/UI/mainwindow.py:602
+#: ../Thuban/UI/mainwindow.py:862
+#, python-format
+msgid "Can't open the file '%s'."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:589
+msgid "Select an image file"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:601
+msgid "Add Image Layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:629
+msgid "Add Layer from database"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:630
+#, python-format
+msgid "Can't open the database table '%s'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:719
+#, python-format
+msgid "Copy of `%s'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:749
+#, python-format
+msgid "Layer Table: %s"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:764
+#, python-format
+msgid "Map Projection: %s"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:779
+#, python-format
+msgid "Layer Projection: %s"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:812
+msgid "Join Layer with Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:834 ../Thuban/UI/mainwindow.py:1165
+msgid "Legend"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:848 ../Thuban/UI/mainwindow.py:861
+msgid "Open Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:850
+msgid "DBF Files (*.dbf)"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:873
+msgid "Pick the tables to close:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:874
+msgid "Close Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:894
+msgid "Pick the table to show:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:895
+msgid "Show Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:906
+msgid "Join Tables"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:929
+msgid "Pick the table to rename:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:930 ../Thuban/UI/mainwindow.py:942
+msgid "Rename Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:942
+msgid "Table Title:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Map Title:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:991
+msgid "Rename Map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Layer Title:"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1004
+msgid "Rename Layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1057
+#, python-format
+msgid "Thuban - %s"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1059
+msgid "Thuban"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1154
+msgid "&New Session"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1155
+msgid "Start a new session"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1156
+msgid "&Open Session..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1157
+msgid "Open a session file"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1158
+msgid "&Save Session"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1159
+msgid "Save this session to the file it was opened from"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1160
+msgid "Save Session &As..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1161
+msgid "Save this session to a new file"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1162
+msgid "Session &Tree"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1164
+msgid "Toggle on/off the session tree analysis window"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1167
+msgid "Toggle Legend on/off"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1168
+msgid "&Database Connections..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1171
+msgid "E&xit"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1172
+msgid "Finish working with Thuban"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1175
+msgid "&About..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1176
+msgid "Info about Thuban authors, version and modules"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1180 ../Thuban/UI/mainwindow.py:1228
+msgid "Pro&jection..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1181
+msgid "Set or change the map projection"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1183
+msgid "&Zoom in"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1184
+msgid "Switch to map-mode 'zoom-in'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1186
+msgid "Zoom &out"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1187
+msgid "Switch to map-mode 'zoom-out'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1189
+msgid "&Pan"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1190
+msgid "Switch to map-mode 'pan'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1192
+msgid "&Identify"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1194
+msgid "Switch to map-mode 'identify'"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1196
+msgid "&Label"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1197
+msgid "Add/Remove labels"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1199
+msgid "&Full extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1200
+msgid "Zoom to the full map extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1202
+msgid "&Full layer extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1203
+msgid "Zoom to the full layer extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1205
+msgid "&Full selection extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1207
+msgid "Zoom to the full selection extent"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1209
+msgid "E&xport"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1210
+msgid "Export the map to file"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1211
+msgid "Prin&t"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1212
+msgid "Print the map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1213 ../Thuban/UI/mainwindow.py:1299
+msgid "&Rename..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1214
+msgid "Rename the map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1215
+msgid "&Add Layer..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1216
+msgid "Add a new layer to the map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1217
+msgid "&Add Image Layer..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1218
+msgid "Add a new image layer to the map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1220
+msgid "Add &Database Layer..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1221
+msgid "Add a new database layer to active map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1223
+msgid "&Remove Layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1224
+msgid "Remove selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1230
+msgid "Specify projection for selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1231
+msgid "&Duplicate"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1232
+msgid "Duplicate selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1234
+msgid "Re&name ..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1235
+msgid "Rename selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1237
+msgid "&Raise"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1238
+msgid "Raise selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1240
+msgid "&Lower"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1241
+msgid "Lower selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1243
+msgid "&Show"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1244
+msgid "Make selected layer visible"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1246
+msgid "&Hide"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1247
+msgid "Make selected layer unvisible"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1249
+msgid "Show Ta&ble"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1250
+msgid "Show the selected layer's table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1252
+msgid "&Properties..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1254
+msgid "Edit the properties of the selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1255
+msgid "&Join Table..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1257
+msgid "Join and attach a table to the selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1260
+msgid "&Top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1261
+msgid "Put selected layer to the top"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1263
+msgid "&Bottom"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1264
+msgid "Put selected layer to the bottom"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1266
+msgid "&Visible"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1268
+msgid "Toggle visibility of selected layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1285
+msgid "&Unjoin Table..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1287
+msgid "Undo the last join operation"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1294
+msgid "&Open..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1295
+msgid "Open a DBF-table from a file"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1296
+msgid "&Close..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1298
+msgid "Close one or more tables from a list"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1301
+msgid "Rename one or more tables"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1302
+msgid "&Show..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1304
+msgid "Show one or more tables in a dialog"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1305
+msgid "&Join..."
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1307
+msgid "Join two tables creating a new one"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1331
+msgid "&File"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1337
+msgid "&Map"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1338
+msgid "&Layer"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1352
+msgid "&Table"
+msgstr ""
+
+#: ../Thuban/UI/mainwindow.py:1358
+msgid "&Help"
+msgstr ""
+
+#: ../Thuban/UI/menu.py:90
+#, python-format
+msgid "Submenu %s doesn't exist"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:62 ../Thuban/UI/projdialog.py:776
+msgid "Transverse Mercator"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:63 ../Thuban/UI/projdialog.py:842
+msgid "Universal Transverse Mercator"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:64 ../Thuban/UI/projdialog.py:918
+msgid "Lambert Conic Conformal"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:65 ../Thuban/UI/projdialog.py:66
+#: ../Thuban/UI/projdialog.py:968
+msgid "Geographic"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:110
+msgid "Import..."
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:113
+msgid "Export..."
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:122
+msgid "Show EPSG:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:124
+msgid "Normal"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:127
+msgid "Deprecated"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:138
+msgid "Edit"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:148
+msgid "Name:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:156
+msgid "Projection:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:167 ../Thuban/UI/projdialog.py:648
+msgid "<Unknown>"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:183
+msgid "New"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:186
+msgid "Add to List"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:190
+msgid "Update"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:295
+#, python-format
+msgid ""
+"Warnings when reading \"%s\":\n"
+"\n"
+"%s"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:306
+msgid "Import"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:319 ../Thuban/UI/projdialog.py:617
+msgid "Warnings"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:337 ../Thuban/UI/tableview.py:386
+msgid "Export"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:389
+msgid "The following error occured:\n"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:391
+msgid "Error"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:460
+msgid "No Projections selected"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:470
+#, python-format
+msgid "Source of Projection: %s"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:502
+msgid "Multiple Projections selected"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:649
+msgid "Airy"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:650
+msgid "Bessel 1841"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:651
+msgid "Clarke 1866"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:652
+msgid "Clarke 1880"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:653
+msgid "GRS 1980 (IUGG, 1980)"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:654
+msgid "International 1909 (Hayford)"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:655
+msgid "WGS 84"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:667
+msgid "Ellipsoid:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:716
+msgid ""
+"Thuban does not know the parameters\n"
+"for the current projection and cannot\n"
+"display a configuration panel.\n"
+"\n"
+"The unidentified set of parameters is:\n"
+"\n"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:762
+msgid "Latitude:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:764
+msgid "Longitude:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:766 ../Thuban/UI/projdialog.py:910
+msgid "False Easting:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:768 ../Thuban/UI/projdialog.py:912
+msgid "False Northing:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:770
+msgid "Scale Factor:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:821
+msgid "Propose"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:823
+msgid "Southern Hemisphere"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:833
+msgid "Zone:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:870
+msgid "Can not propose: No bounding box found."
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:871 ../Thuban/UI/projdialog.py:1008
+msgid "Projection: Propose UTM Zone"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:901
+msgid "Latitude of first standard parallel:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:904
+msgid "Latitude of second standard parallel:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:906
+msgid "Central Meridian:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:908
+msgid "Latitude of origin:"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:958
+msgid "Degrees"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:959
+msgid "Radians"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:992
+msgid "Source Data is in: "
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:1021
+msgid "The current map extent center lies in UTM Zone"
+msgstr ""
+
+#: ../Thuban/UI/projdialog.py:1031
+msgid "Take"
+msgstr ""
+
+#: ../Thuban/UI/projlist.py:51
+msgid "Available Projections"
+msgstr ""
+
+#: ../Thuban/UI/projlist.py:112
+msgid "<None>"
+msgstr ""
+
+#: ../Thuban/UI/projlist.py:117
+#, python-format
+msgid "%s (current)"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:41
+msgid "GDAL image information unavailable. See About box for details."
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:49
+msgid "Extent (lat-lon): None"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:56
+msgid "Image Properties"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:61
+#, python-format
+msgid "Source: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:71
+#, python-format
+msgid "Driver: %s"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:74
+#, python-format
+msgid "Size: %ix%i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:77
+#, python-format
+msgid "Number of Bands: %i"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:93
+msgid "Mask Type"
+msgstr ""
+
+#: ../Thuban/UI/rasterlayerproperties.py:99
+msgid "Opacity:"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:381
+msgid "Replace Selection"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:382
+msgid "Refine Selection"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:383
+msgid "Add to Selection"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:385
+msgid "Query"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:387
+msgid "Export Selection"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:413
+msgid "Selection"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:455
+#, python-format
+msgid "%i rows (%i selected), %i columns"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:535
+msgid "Export Table To"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:536
+msgid "DBF Files (*.dbf)|*.dbf|"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:537
+msgid "CSV Files (*.csv)|*.csv|"
+msgstr ""
+
+#: ../Thuban/UI/tableview.py:538
+msgid "All Files (*.*)|*.*"
+msgstr ""
+
+#: ../Thuban/UI/tree.py:226
+msgid "Session"
+msgstr ""
+
+#: ../Thuban/UI/view.py:285
+msgid "Export Map"
+msgstr ""
Added: packages/thuban/branches/upstream/current/setup.cfg
===================================================================
--- packages/thuban/branches/upstream/current/setup.cfg 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/setup.cfg 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,16 @@
+[sdist]
+formats=bztar,zip
+
+[bdist_rpm]
+release = 1
+doc_files = README
+ libraries/pyshapelib/README.pyshapelib
+ libraries/pyshapelib/COPYING.pyshapelib
+ libraries/pyprojection/LICENSE.pyprojection
+prep_script = bdist_rpm_prep
+build_script = bdist_rpm_build
+install_script = bdist_rpm_install
+prefix = /usr
+
+[bdist_inno]
+copyright = Copyright © 2001-2003 Intevation GmbH
Added: packages/thuban/branches/upstream/current/setup.py
===================================================================
--- packages/thuban/branches/upstream/current/setup.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/setup.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1220 @@
+# Copyright (c) 2001, 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""Distutils setup script for Thuban."""
+
+__version__ = "$Revision: 2729 $"
+
+# Configuration:
+#
+# depending on your platform you may have to configure some variables by
+# hand below.
+#
+
+import sys
+import os
+from types import TupleType
+import glob
+from distutils.core import setup, Extension, Command
+from distutils.command.install import install, INSTALL_SCHEMES, subst_vars
+from distutils.command.build_py import build_py
+from distutils.command.bdist_rpm import bdist_rpm
+from distutils.command.build_ext import build_ext
+from distutils.file_util import write_file
+from distutils.filelist import FileList
+from distutils.util import convert_path, change_root
+
+from distutils import archive_util, dir_util
+import distutils
+
+from string import split
+import string
+
+# config script parameter list indices
+CS_DEFS, CS_INCDIRS, CS_LIBDIRS, CS_LIBS, CS_NUM_PARAMS = range(5)
+
+# support for gdal is on by default, but under posix we try to
+# detect it anyway. Set this to False to disable GDAL.
+include_gdal = True
+
+if os.name == "posix":
+ ###################################################################
+ # Posix configuration. Adapt this if you're running some kind of
+ # Unix like system.
+
+ # Directories where Proj4 is installed
+ proj4_prefix = "/usr/local/"
+ proj4_incdir = os.path.join(proj4_prefix, "include")
+ proj4_libdir = os.path.join(proj4_prefix, "lib")
+ proj4_lib = "proj"
+
+
+ # You shouldn't have to modify anything below here
+ ###################################################################
+
+ # The installation prefix (similar to autoconf's --prefix). This is
+ # only the default value, you can override it on the command line
+ # with the install command's --prefix option.
+ #
+ # Note that there's a separate prefix option for the bdist_rpm
+ # command completely independent of this one.
+ prefix = "/usr/local/"
+
+ # Whether to create the thubaninit module. You can override this
+ # value on the commandline with the --create-init-module to the
+ # install command.
+ create_init_module = 1
+
+ # On POSIX-systems we run wxgtk-config to determine the C++-compiler
+ # flags
+ wx_config_script = "wx-config"
+ # These lists will be filled automatically below
+ wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
+
+ gdal_config_script = "gdal-config"
+ gdal_cs_params = [[] for i in range(CS_NUM_PARAMS)]
+
+elif os.name == "nt":
+ #################################################################
+ # Windows configuration.
+ #
+
+ basedir = os.path.dirname(sys.argv[0])
+
+ # Directories where Proj4 is installed
+ proj4_prefix = os.path.join(basedir, "..", "proj-4.4.9", "src")
+ proj4_incdir = proj4_prefix
+ proj4_libdir = proj4_prefix
+ proj4_lib = "proj_i"
+
+ # Define include and lib directories for wxWindows and
+ wx_prefix = os.path.join(basedir, "..", "wxPython-2.6.3.3")
+ wx_inc = [os.path.join(wx_prefix, 'lib', 'vc_dll', 'mswuh'),
+ os.path.join(wx_prefix, "include")]
+ wx_lib = [os.path.join(wx_prefix, "lib", "vc_dll")]
+
+ # Define include and lib directories for GDAL
+ gdal_prefix = os.path.join(basedir, "..", "gdal-1.3.2")
+ gdal_inc = [os.path.join(gdal_prefix, 'alg'),
+ os.path.join(gdal_prefix, 'ogr'),
+ os.path.join(gdal_prefix, 'port'),
+ os.path.join(gdal_prefix, 'gcore'),
+ os.path.join(gdal_prefix, 'core')]
+ gdal_lib = [gdal_prefix]
+
+ #
+ # Unless you use a wxPython version other than 2.4.0, you probably
+ # shouldn't have to modify anything below here
+ ##################################################################
+
+ # Installation prefix. Just install relative to current directory by
+ # default. This is only the default value, you can override it on
+ # the command line with the install command's --prefix option
+ prefix = r"install"
+
+ # Whether to create the thubaninit module. You can override this
+ # value on the commandline with the --create-init-module to the
+ # install command. By default we don't create it under NT because we
+ # most often run install only as part of bdist_inno where we can't
+ # really create because it needs information only known at install
+ # time.
+ create_init_module = 0
+
+ # There doesn't seem to be an easy way to get at the wx compiler
+ # flags, so we define them here. These flags work for us with
+ # wxPython 2.3.1. They may have to be modified for other versions.
+
+ # there's no config script.
+ wx_config_script = ""
+
+ wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
+
+ # the values of wx_defs and wx_libs. copied from the wxPython
+ # setup.py
+ wx_cs_params[CS_DEFS] = \
+ [ ('WIN32', None), # Some of these are no longer
+ ('__WIN32__', None), # necessary. Anybody know which?
+ ('_WINDOWS', None),
+ ('__WINDOWS__', None),
+ ('WINVER', '0x0400'),
+ ('__WIN95__', None),
+ ('STRICT', None),
+
+ ('__WXMSW__', None),
+ ('WXUSINGDLL', '1'),
+
+ ('SWIG_GLOBAL', None),
+ ('HAVE_CONFIG_H', None),
+ ('WXP_USE_THREAD', '1'),
+ ]
+
+ wx_cs_params[CS_INCDIRS] = wx_inc
+ wx_cs_params[CS_LIBDIRS] = wx_lib
+ wx_cs_params[CS_LIBS] = ["wxmsw26uh"] \
+ + ['kernel32', 'user32', 'gdi32', 'comdlg32',
+ 'winspool', 'winmm', 'shell32', 'oldnames',
+ 'comctl32', 'odbc32', 'ole32', 'oleaut32',
+ 'uuid', 'rpcrt4', 'advapi32', 'wsock32']
+
+ gdal_config_script = ""
+ gdal_cs_params = [[] for i in range(CS_NUM_PARAMS)]
+
+ gdal_cs_params[CS_INCDIRS] = gdal_inc
+ gdal_cs_params[CS_LIBDIRS] = gdal_lib
+ gdal_cs_params[CS_LIBS] = ["gdal_i"]
+
+else:
+ raise RuntimeError("Unsupported platform " + os.name)
+
+
+######################################################################
+#
+# There's nothing beyond this point that has to be modified for a
+# normal installation
+#
+######################################################################
+
+
+#
+# Functions to determine wxWindows config on POSIX systems
+#
+
+def run_script(cmdline):
+ """Run command and return its stdout or none in case of errors"""
+ pipe = os.popen(cmdline)
+ result = pipe.read()
+ if pipe.close() is not None:
+ print '"' + cmdline + '"', 'failed'
+ return None
+ return result
+
+
+def run_cs_script(command, store):
+ # first, determine the C++ preprocessor flags Use --cflags here
+ # because it seems that older version don't have --cxxflags and
+ # newer ones return the same result for both
+ flags = run_script(command + ' --cflags ')
+ if flags is None:
+ return False
+ for flag in split(flags):
+ start = flag[:2]
+ value = flag[2:]
+ if start == "-I":
+ store[CS_INCDIRS].append(value)
+ elif start == "-D":
+ store[CS_DEFS].append((value, None))
+
+ # determine the library flags
+ flags = run_script(command + ' --libs')
+ if flags is None:
+ return False
+ for flag in split(flags):
+ start = flag[:2]
+ value = flag[2:]
+ if start == "-L":
+ store[CS_LIBDIRS].append(value)
+ elif start == "-l":
+ store[CS_LIBS].append(value)
+
+ return True
+
+if wx_config_script:
+ # if there's a wx config script, run it to determine the configuration
+ run_cs_script(wx_config_script, wx_cs_params)
+
+if gdal_config_script:
+ # if there's a gdal config script, run it to determine the configuration
+ include_gdal = include_gdal \
+ and run_cs_script(gdal_config_script, gdal_cs_params)
+
+#
+# Define some extension and python modules
+#
+# The C-extension names are prefixed with "Lib." so they get put into
+# the Lib/ subdirectory. Lib/ is not really a package but distutils
+# doesn't care
+
+# subdirectory containing the distutil extensions
+ext_dir = "libraries"
+
+# subdirectory with some shapelib files
+shp_dir = ext_dir + "/shapelib"
+
+# lists to fill with the module descriptions
+extensions = []
+py_modules = []
+
+
+#
+# Thuban specific modules
+#
+
+wxproj_extension = Extension("Lib.wxproj",
+ [ext_dir + "/thuban/wxproj.cpp"],
+ include_dirs = ([shp_dir, proj4_incdir,
+ ext_dir + "/pyshapelib/"]
+ + wx_cs_params[CS_INCDIRS]),
+ define_macros = wx_cs_params[CS_DEFS],
+ library_dirs = [proj4_libdir] +
+ wx_cs_params[CS_LIBDIRS],
+ libraries = [proj4_lib] + wx_cs_params[CS_LIBS])
+extensions.append(wxproj_extension)
+
+
+#
+# shapelib wrappers are also distributed with thuban
+#
+
+extensions.append(Extension("Lib.shapelibc",
+ [ext_dir + "/pyshapelib/shapelib_wrap.c",
+ shp_dir + "/shpopen.c",
+ shp_dir + "/shptree.c"],
+ include_dirs = [shp_dir]))
+extensions.append(Extension("Lib.shptree",
+ [ext_dir + "/pyshapelib/shptreemodule.c"],
+ include_dirs = [shp_dir]))
+extensions.append(Extension("Lib.dbflibc",
+ [ext_dir + "/pyshapelib/dbflib_wrap.c",
+ shp_dir + "/dbfopen.c"],
+ include_dirs = [shp_dir],
+ define_macros = [("HAVE_UPDATE_HEADER", "1")]))
+for name in ("shapelib", "dbflib"):
+ py_modules.append(ext_dir + "/pyshapelib/" + name)
+
+#
+# PROJ4 bindings are also distributed with thuban
+#
+extensions.append(Extension("Lib.Projectionc",
+ [ext_dir + "/pyprojection/Projection_wrap.c"],
+ include_dirs = [proj4_incdir],
+ library_dirs = [proj4_libdir],
+ libraries = [proj4_lib]))
+py_modules.append(ext_dir + "/pyprojection/Projection")
+
+
+#
+# Data files
+#
+
+data_files = []
+
+# Resources
+for d, patterns in [("Resources/Bitmaps",
+ ("Resources/Bitmaps/*.xpm",)),
+ ("Resources/Projections",
+ ("Resources/Projections/*.proj",)),
+ ("Resources/XML",
+ ("Resources/XML/*.dtd",)),
+ ("Extensions/importAPR/samples",
+ ("Extensions/importAPR/samples/README",
+ "Extensions/importAPR/samples/*.apr")),
+ ]:
+ for pattern in patterns:
+ data_files.append((d, glob.glob(pattern)))
+if os.path.isdir("Resources/Locale"):
+ for d in os.listdir("Resources/Locale"):
+ data_files.append(("Resources/Locale/" + d +"/LC_MESSAGES",
+ ["Resources/Locale/"+ d +"/LC_MESSAGES/thuban.mo"]))
+
+#add the Lib content to the output
+if os.path.isdir("Lib"):
+ for d in os.listdir("Lib"):
+ data_files.append(("Lib", ["Lib/"+d]))
+
+
+#
+# Command definitions
+#
+# So far distutils are only meant to distribute python extensions, not
+# complete applications, so we have to redefine a few commands
+#
+
+
+# Much of the data_dist command is directly copied from the distutils'
+# sdist command
+class data_dist(Command):
+
+ description = "create a data distribution (tarball, zip file, etc.)"
+
+ user_options = [
+ ('formats=', None,
+ "formats for source distribution (comma-separated list)"),
+ ('keep-temp', 'k',
+ "keep the distribution tree around after creating " +
+ "archive file(s)"),
+ ('dist-dir=', 'd',
+ "directory to put the source distribution archive(s) in "
+ "[default: dist]"),
+ ]
+
+ boolean_options = ['keep-temp']
+
+ def initialize_options (self):
+ self.formats = None
+ self.keep_temp = 0
+ self.dist_dir = None
+
+ def finalize_options (self):
+ self.ensure_string_list('formats')
+ if self.formats is None:
+ self.formats = ["zip"]
+ bad_format = archive_util.check_archive_formats(self.formats)
+ if bad_format:
+ raise DistutilsOptionError, \
+ "unknown archive format '%s'" % bad_format
+
+ if self.dist_dir is None:
+ self.dist_dir = "dist"
+
+
+ def run(self):
+ # 'filelist' contains the list of files that will make up the
+ # manifest
+ self.filelist = FileList()
+
+ # Do whatever it takes to get the list of files to process.
+ # File list is accumulated in 'self.filelist'.
+ self.get_file_list()
+
+ # Otherwise, go ahead and create the source distribution tarball,
+ # or zipfile, or whatever.
+ self.make_distribution()
+
+ def get_file_list(self):
+ """Figure out the list of files to include in the data
+ distribution, and put it in 'self.filelist'.
+ """
+ self.filelist.findall("Data")
+ self.filelist.include_pattern("*", anchor = 0)
+ self.filelist.exclude_pattern(r'/(RCS|CVS)/.*', is_regex=1)
+ self.filelist.sort()
+ self.filelist.remove_duplicates()
+
+ def make_release_tree(self, base_dir, files):
+ """Create the directory tree that will become the source
+ distribution archive. All directories implied by the filenames in
+ 'files' are created under 'base_dir', and then we hard link or copy
+ (if hard linking is unavailable) those files into place.
+ Essentially, this duplicates the developer's source tree, but in a
+ directory named after the distribution, containing only the files
+ to be distributed.
+ """
+ # Create all the directories under 'base_dir' necessary to
+ # put 'files' there; the 'mkpath()' is just so we don't die
+ # if the manifest happens to be empty.
+ self.mkpath(base_dir)
+ dir_util.create_tree(base_dir, files,
+ verbose=self.verbose, dry_run=self.dry_run)
+
+ # And walk over the list of files, either making a hard link (if
+ # os.link exists) to each one that doesn't already exist in its
+ # corresponding location under 'base_dir', or copying each file
+ # that's out-of-date in 'base_dir'. (Usually, all files will be
+ # out-of-date, because by default we blow away 'base_dir' when
+ # we're done making the distribution archives.)
+
+ if hasattr(os, 'link'): # can make hard links on this system
+ link = 'hard'
+ msg = "making hard links in %s..." % base_dir
+ else: # nope, have to copy
+ link = None
+ msg = "copying files to %s..." % base_dir
+
+ if not files:
+ self.warn("no files to distribute -- empty manifest?")
+ else:
+ self.announce(msg)
+ for file in files:
+ if not os.path.isfile(file):
+ self.warn("'%s' not a regular file -- skipping" % file)
+ else:
+ dest = os.path.join(base_dir, file)
+ self.copy_file(file, dest, link=link)
+
+
+ def make_distribution (self):
+ """Create the source distribution(s). First, we create the release
+ tree with 'make_release_tree()'; then, we create all required
+ archive files (according to 'self.formats') from the release tree.
+ Finally, we clean up by blowing away the release tree (unless
+ 'self.keep_temp' is true). The list of archive files created is
+ stored so it can be retrieved later by 'get_archive_files()'.
+ """
+ # Don't warn about missing meta-data here -- should be (and is!)
+ # done elsewhere.
+ base_dir = "Thuban-data-" + self.distribution.get_version()
+ base_name = os.path.join(self.dist_dir, base_dir)
+
+ self.make_release_tree(base_dir, self.filelist.files)
+ archive_files = [] # remember names of files we create
+ for fmt in self.formats:
+ file = self.make_archive(base_name, fmt, base_dir=base_dir)
+ archive_files.append(file)
+
+ self.archive_files = archive_files
+
+ if not self.keep_temp:
+ dir_util.remove_tree(base_dir, self.verbose, self.dry_run)
+
+
+
+class InstallLocal(Command):
+
+ """
+ A new install command to just link (or copy, on non-POSIX systems)
+ the extension modules to the top directory so that Thuban can be run
+ directly from the source dir.
+ """
+
+ description =\
+ "Create some symlinks so you can run thuban from the source directory"
+
+ user_options = [
+ ('skip-build', None, "skip the build steps"),
+ ('create-init-module', None,
+ "Create the thubaninit.py module to ease use of Thuban as a library"),
+ ('dont-create-init-module', None,
+ "Do not create the thubaninit.py module"),
+ ]
+
+ boolean_options = ["create-init-module"]
+ negative_opt = {'dont-create-init-module' : 'create-init-module'}
+
+
+ def initialize_options (self):
+ self.extensions = None
+ self.build_dir = None
+ self.skip_build = None
+ self.create_init_module = None
+
+ def finalize_options (self):
+ self.set_undefined_options("install",
+ ("build_lib", "build_dir"),
+ ('skip_build', 'skip_build'))
+ self.extensions = self.distribution.ext_modules
+ if self.create_init_module is None:
+ # by default we create the init module
+ self.create_init_module = 1
+
+ def run(self):
+ # Make sure we have built everything we need first
+ self.build()
+
+ # now do the work. Simply link or copy the Lib dir
+ libdir = os.path.join(self.build_dir, "Lib")
+ if os.name == "posix":
+ # on posix, just link the Lib dir
+ self.link_dir(libdir, "Lib")
+ else:
+ self.copy_tree(libdir, "Lib")
+
+ # create the init module if desired
+ if self.create_init_module:
+ # create the init module
+ initfilename = "thubaninit.py"
+ contents = thubaninit_contents("")
+ self.execute(write_file, (initfilename, contents),
+ "Create %s" % initfilename)
+
+ def link_dir(self, src, dest):
+ """Create a symbolic link dest pointing to src"""
+ if self.verbose:
+ self.announce("symlinking %s -> %s" % (src, dest))
+ if self.dry_run:
+ return
+
+ if not (os.path.exists(dest) and os.path.samefile(src, dest)):
+ os.symlink(src, dest)
+
+ def build (self):
+ if not self.skip_build:
+ if self.distribution.has_pure_modules():
+ self.run_command('build_py')
+ if self.distribution.has_ext_modules():
+ self.run_command('build_ext')
+
+
+
+class thuban_build_py(build_py):
+
+ """
+ A new build_py that can deal with both packages and modules in one
+ distribution.
+ """
+
+ # FIXME: When Thuban can rely on Python 2.3 as the oldest supported
+ # Python release we don't need to override the run and
+ # find_all_modules methods anymore. distutils will allow both python
+ # modules and packages starting with 2.3.
+
+ def run(self):
+ """The same the as the original in build_py revision 1.33 except
+ that this allows both packages and modules to be in one
+ distribution
+ """
+ if not self.py_modules and not self.packages:
+ return
+
+ # Now we're down to two cases: 'py_modules' only and 'packages' only.
+ if self.py_modules:
+ self.build_modules()
+ if self.packages:
+ self.build_packages()
+
+ self.byte_compile(self.get_outputs(include_bytecode=0))
+
+ def find_modules (self):
+ """Thuban specific version of build_py.find_modules. Unlike the
+ original version, we assume that the modules in self.py_modules
+ can contain directories and are all to be placed into the same
+ subdirectory, Lib, in the build directory. This is achieved by
+ returning the modules as a list (package, module, filename)
+ where package is 'Lib', module is the basename of the module name
+ and filename is the filename relative to the package root.
+ """
+ modules = []
+ for module in self.py_modules:
+ module_base = os.path.basename(module)
+ module_file = module + ".py"
+ if not self.check_module(module, module_file):
+ continue
+
+ modules.append(("Lib", module_base, module_file))
+ return modules
+
+ def find_all_modules (self):
+ # same as find_all_modules of the original build_py command
+ # (rev. 1.33) but handle installations with both modules and
+ # packages. Needed here so tha the get_outputs works correctly
+ modules = []
+ if self.py_modules:
+ modules.extend(self.find_modules())
+ if self.packages:
+ for package in self.packages:
+ package_dir = self.get_package_dir(package)
+ m = self.find_package_modules(package, package_dir)
+ modules.extend(m)
+
+ return modules
+
+
+thubaninit_contents_start = """
+# This module was automatically generated by Thuban's install script
+'''Import this module once per program (best place is probably the file
+that ends up as your __main__ module) to be able to import Thuban
+afterwards.
+
+Usage:
+
+import thubaninit
+import Thuban
+'''
+import sys, os
+"""
+
+thubaninit_contents_thubaninitdir = """
+sys.path.insert(0, %(thubandir)s)
+"""
+thubaninit_contents_otherdirs = """
+# Put the Lib dir into the path. The Lib dir contains some extra Python
+# modules
+import Thuban
+thubandir = os.path.join(Thuban.__path__[0], '..')
+dir = os.path.join(thubandir, "Lib")
+if os.path.isdir(dir):
+ sys.path.insert(0, dir)
+"""
+
+def thubaninit_contents(thubandir):
+ """Return the contents of the the thubaninit file as a list of lines.
+
+ The parameter thubandir is the parent directory where the Thuban/
+ package or the empty string if the thubaninit file itself will be
+ located in that direcory as well.
+ """
+ contents = thubaninit_contents_start
+ if thubandir:
+ thubandir = repr(thubandir)
+ contents += thubaninit_contents_thubaninitdir % locals()
+ contents += thubaninit_contents_otherdirs
+ return contents.split("\n")
+
+
+class ThubanInstall(install):
+
+ """
+ Thuban specific install command.
+
+ Extend the standard install command to symlink the installed script
+ to $prefix/bin/
+ """
+
+ user_options = install.user_options[:]
+ user_options.extend([("do-symlink", None,
+ "Create a symlink to the script in <prefix>/bin."
+ "(default on posix systems and only relevant there)"),
+
+ ("extra-files", None,
+ "List of filenames or (src, dest) pairs describing"
+ " extra files to install "
+ "(can only be set from within setup.py"),
+
+ ("create-init-module=", None,
+ "If true, create a module in the site-packages"
+ " directory that tweaks sys.path to let you easily"
+ " import thuban modules from outside of thuban."),
+ ("init-module-dir=", None,
+ "Directory in which to create the init module."
+ " Defaults to Python's site-packages directory."),
+ ])
+
+ boolean_options = install.boolean_options[:]
+ boolean_options.append("do-symlink")
+ boolean_options.append("create-init-module")
+
+ def initialize_options(self):
+ self.do_symlink = None
+ self.extra_files = []
+
+ # initialize the create_init_module flag from the global
+ # determined at runtime
+ self.create_init_module = create_init_module
+ self.init_module_dir = None
+ install.initialize_options(self)
+
+ def finalize_options(self):
+ if self.do_symlink is None:
+ if os.name == "posix":
+ self.do_symlink = 1
+ else:
+ self.do_symlink = 0
+ install.finalize_options(self)
+ self.expand_with_pure_python_dirs(["init_module_dir"])
+
+ def expand_with_pure_python_dirs(self, attrs):
+ """Expand the attributes with default values of base and platbase"""
+ # it seems that the values for "prefix" and "exec_prefix" in
+ # self.config_vars are the corresponding values used by the
+ # python interpreter, so we just assign these to "base" and
+ # "platbase".
+ config_vars = self.config_vars.copy()
+ config_vars["base"] = self.config_vars["prefix"]
+ config_vars["platbase"] = self.config_vars["exec_prefix"]
+ for attr in attrs:
+ val = getattr(self, attr)
+ if val is not None:
+ if os.name == 'posix':
+ val = os.path.expanduser(val)
+ val = subst_vars(val, config_vars)
+ setattr(self, attr, val)
+
+ def select_scheme(self, scheme):
+ """Extend the inherited method to set init_module_dir"""
+ install.select_scheme(self, scheme)
+ # only set init_module_dir if it wasn't set by the user
+ if self.init_module_dir is None:
+ self.init_module_dir = INSTALL_SCHEMES[scheme]['purelib']
+
+ def convert_paths(self, *args):
+ """Extend the inherited method so that we can remember some filename
+ """
+ # remember the installation directory before its root gets
+ # changed
+ self.install_lib_orig = self.install_lib
+ apply(install.convert_paths, (self,) + args)
+
+ def run(self):
+ install.run(self)
+ for item in self.extra_files:
+ if type(item) == TupleType:
+ src, dest = item
+ else:
+ src = dest = item
+ self.copy_file(convert_path(src),
+ os.path.join(self.root, convert_path(dest)))
+
+ if os.name == "posix" and self.do_symlink:
+ install_scripts = self.install_scripts
+ if self.root:
+ install_scripts = install_scripts[len(self.root):]
+ scriptfile = os.path.join(install_scripts, "thuban.py")
+ bindir = os.path.join(self.prefix, "bin")
+ if self.root:
+ bindir = change_root(self.root, bindir)
+ binfile = os.path.join(bindir, "thuban")
+ self.mkpath(bindir)
+ self.link_file(scriptfile, binfile)
+
+ if self.create_init_module:
+ # create the init module
+ initfilename = self.thuban_init_filename()
+ if self.root:
+ initfilename = change_root(self.root, initfilename)
+ contents = thubaninit_contents(self.install_lib_orig)
+ self.mkpath(os.path.dirname(initfilename))
+ self.execute(write_file, (initfilename, contents),
+ "Create %s" % initfilename)
+
+ def link_file(self, src, dest):
+ """Create a symbolic link dest pointing to src.
+
+ Unlike the symlink variant of the command object's copy_file
+ method, this method even performs the link if src doesn't exist.
+ This is useful when installing with an alternat root directory"""
+ if self.verbose:
+ self.announce("symlinking %s -> %s" % (src, dest))
+ if self.dry_run:
+ return
+
+ if not os.path.exists(dest):
+ os.symlink(src, dest)
+
+ def thuban_init_filename(self):
+ """Return the filename for the init-module"""
+ # Since we override the normal install dirs to point to our own
+ # prefix we have to reach into installed
+ return self.init_module_dir + "/thubaninit.py"
+
+ def get_outputs (self):
+ outputs = install.get_outputs(self)
+ for item in self.extra_files:
+ if type(item) == TupleType:
+ src, dest = item
+ else:
+ src = dest = item
+ outputs.append(os.path.join(self.root, convert_path(dest)))
+ if os.name == "posix" and self.do_symlink:
+ bindir = os.path.join(self.prefix, "bin")
+ if self.root:
+ bindir = change_root(self.root, bindir)
+ binfile = os.path.join(bindir, "thuban")
+ outputs.append(binfile)
+ if self.create_init_module:
+ initfilename = self.thuban_init_filename()
+ if self.root:
+ initfilename = change_root(self.root, initfilename)
+ outputs.append(initfilename)
+ return outputs
+
+
+# scripts to override some of the commands put into the spec-file by the
+# bdist_rpm command.
+
+bdist_rpm_prep_script = '''
+%setup
+cp libraries/pyshapelib/{README,README.pyshapelib}
+cp libraries/pyshapelib/{COPYING,COPYING.pyshapelib}
+cp libraries/pyprojection/{LICENSE,LICENSE.pyprojection}
+'''
+
+bdist_rpm_build_script = '''
+env PATH="$PATH:%(prefix)s/lib/wxPython/bin:/usr/lib/wxPython/bin" CFLAGS="$RPM_OPT_FLAGS" %(python)s setup.py build
+'''
+
+bdist_rpm_install_script = '''
+%(python)s setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES \
+ --prefix=%(prefix)s
+'''
+
+
+class thuban_bdist_rpm(bdist_rpm):
+
+ """Thuban specific RPM distribution command"""
+
+ user_options = bdist_rpm.user_options[:]
+ user_options.extend([("prefix=", None, "Install prefix for the RPM"),
+ ])
+
+ def initialize_options(self):
+ # per default, RPMs are installed in /usr
+ self.prefix = "/usr/"
+
+ # create the scripts we want to override. We actually fill them
+ # with contents later because some values we put into those
+ # scripts such as the python interpreter to use are only known
+ # then.
+ open("bdist_rpm_prep", "w").close()
+ open("bdist_rpm_build", "w").close()
+ open("bdist_rpm_install", "w").close()
+ bdist_rpm.initialize_options(self)
+
+ def _make_spec_file(self):
+ # create the scripts for the spec-file. Now we know the python
+ # interpreter to use.
+ open("bdist_rpm_prep", "w").write(bdist_rpm_prep_script)
+
+ build = bdist_rpm_build_script % {"python": self.python,
+ "prefix": self.prefix}
+ open("bdist_rpm_build", "w").write(build)
+
+ install = bdist_rpm_install_script % {"python": self.python,
+ "prefix": self.prefix}
+ open("bdist_rpm_install", "w").write(install)
+
+ #
+ return bdist_rpm._make_spec_file(self)
+
+
+class bdist_inno(Command):
+
+ """Command to create a windows installer with Inno Setup"""
+
+ description = "Create a windows installer with Inno Setup"
+
+ user_options = [
+ ('skip-build', None, "skip the build steps"),
+ ('bdist-dir=', None,
+ "temporary directory for creating the distribution"),
+ ('run-inno', None,
+ "Run inno-setup to create the installer. On by default on nt"),
+ ('iss-name', None,
+ "The name of the iss file to generate. "
+ "Shouldn't contain directories"),
+
+ # Parameters for the Inno Setup script
+ ('copyright', None, "Copyright notice for the Inno Setup file"),
+ ('default-dir-name', None,
+ "Default installation directory. Defaults to '{pf}\\<name>'"),
+ ('default-group-name', None,
+ "Default program group name. Defaults to <name>'"),
+ ("license-file", None, "File containing the license."),
+ ("output-basename", None,
+ "Base filename for the Inno Setup output "
+ "(defaults to <name>-<version>-<issrevision>)."),
+ ("iss-revision", None,
+ "revision of the generated installer of the package version"),
+
+ ("icons-entries", None,
+ "List if InnoIconItems "
+ "(this can only be set from inside the setup.py script)"),
+ ]
+
+ boolean_options = ["do-symlink"]
+
+ def initialize_options(self):
+ self.skip_build = 0
+ self.bdist_dir = None
+ self.run_inno = None
+ self.iss_name = None
+ self.copyright = ""
+ self.default_dir_name = None
+ self.default_group_name = None
+ self.license_file = None
+ self.output_basename = None
+ self.iss_revision = None
+ self.icons_entries = []
+
+ def finalize_options(self):
+ self.set_undefined_options("install",
+ ('skip_build', 'skip_build'))
+ if self.bdist_dir is None:
+ bdist_base = self.get_finalized_command('bdist').bdist_base
+ self.bdist_dir = os.path.join(bdist_base, 'inno')
+
+ if self.run_inno is None:
+ self.run_inno = os.name == "nt"
+
+ name = self.distribution.get_name()
+ if self.iss_name is None:
+ self.iss_name = name + '.iss'
+
+ if self.default_dir_name is None:
+ self.default_dir_name = "{pf}\\" + name
+ if self.default_group_name is None:
+ self.default_group_name = name
+
+ if self.iss_revision is None:
+ self.iss_revision = 0
+ if self.output_basename is None:
+ self.output_basename = "%s-%s-%d" \
+ % (name, self.distribution.get_version(),
+ int(self.iss_revision))
+
+ def run(self, install_options = None):
+ """Execute the command. install_options if given, should be a
+ directory of additional options to set in the install step"""
+ # Obviously have to build before we can install
+
+ # add gdal to the build
+ for (dirpath, dnames, fnames) in os.walk('gdal'):
+ files_in_dir = []
+ dp = '/'.join(dirpath.split('\\'))
+ for f in fnames:
+ if os.path.isfile(os.path.join(dirpath,f)):
+ files_in_dir.append( dp + '/' + f)
+ if len(files_in_dir) > 0:
+ data_files.append(( dp , files_in_dir))
+ # add thubaninit to the build
+
+
+ if not self.skip_build:
+ self.run_command('build')
+
+ # Install in a temporary directory
+ install = self.reinitialize_command('install')
+ install.root = self.bdist_dir
+ if install_options is not None:
+ for key, value in install_options.items():
+ setattr(install, key, value)
+ if os.name != 'nt':
+ # Must force install to use the 'nt' scheme;
+ install.select_scheme('nt')
+
+ self.announce("installing to %s" % self.bdist_dir)
+ install.ensure_finalized()
+ install.run()
+
+ # Create the iss file
+ iss_file = os.path.join(self.bdist_dir, self.iss_name)
+ self.execute(write_file, (iss_file, self.generate_iss()),
+ "Create Inno Setup script file %s" % iss_file)
+
+ # and invoke
+ if self.run_inno:
+ self.spawn(["iscc", iss_file])
+
+ def generate_iss(self):
+ """Return the contents of the iss file as list of strings, one
+ string per line"""
+
+ # first, turn the icons entries into a more usable form
+ icons = {}
+ for item in self.icons_entries:
+ icons[item.filename] = item
+
+ iss = []
+
+ name = self.distribution.get_name()
+ iss.extend(["[Setup]",
+ "AppName=" + name,
+ "AppVerName=" + name + " "+self.distribution.get_version(),
+ "DefaultDirName=" + self.default_dir_name,
+ "DefaultGroupName=" + self.default_group_name,
+ ])
+ if self.copyright:
+ iss.append("AppCopyright=" + self.copyright)
+ if self.license_file:
+ iss.append("LicenseFile=" + self.license_file)
+
+ iss.append("OutputBasefilename=" + self.output_basename)
+
+ iss.append("")
+ iss.append("[Files]")
+
+ install = self.get_finalized_command("install")
+ install_scripts = self.get_finalized_command("install_scripts")
+ script_files = install_scripts.get_outputs()
+ prefixlen = len(self.bdist_dir) + len(os.sep)
+ for filename in install.get_outputs():
+ filename = filename[prefixlen:]
+ icon = icons.get(filename)
+ dirname = os.path.dirname(filename)
+ if os.name != "nt":
+ # change the separators to \ on non-windos systems
+ filename = string.join(string.split(filename, os.sep), "\\")
+ dirname = string.join(string.split(dirname, os.sep), "\\")
+ line = 'Source: "%s"' % filename
+ if icon is not None:
+ # install it as defined in the icon object
+ backslash = string.rfind(icon.install_name, "\\")
+ if backslash >= 0:
+ dirname = icon.install_name[:backslash]
+ basename = icon.install_name[backslash + 1:]
+ else:
+ dirname = ""
+ basename = icon.install_name
+ line = '%s; DestDir: "%s"; DestName: "%s"' % (line, dirname,
+ basename)
+ else:
+ line = line + '; DestDir: "{app}\\%s"' % (dirname)
+ iss.append(line)
+
+ iss.append("")
+ iss.append("[Icons]")
+ for icon in self.icons_entries:
+ line = 'Name: "{group}\\%s"; Filename: "%s";' \
+ % (icon.title, icon.install_name)
+ iss.append(line)
+
+ return iss
+
+
+class InnoIconItem:
+
+ """Describe one item for the start menu for the Inno Setup installer"""
+
+ def __init__(self, filename, title, install_name = None):
+ self.filename = filename
+ self.title = title
+ if install_name is not None:
+ self.install_name = install_name
+ else:
+ self.install_name = filename
+
+
+class thuban_bdist_inno(bdist_inno):
+
+ """Thuban specific Inno Setup stuff"""
+
+ def run(self):
+ install_options = {
+ "prefix": ".",
+ "install_lib": "$base",
+ "install_data": "$base",
+ "install_scripts": "$base",
+ "warn_dir": 0,
+ "extra_files": ["COPYING", "Lib/proj.dll"],
+ }
+ install_options["extra_files"].extend(self.get_gdal_content())
+
+ # don't make a symlink because we're simulating windows, so
+ # that we can generate the iss-file even on Linux
+ install_options["do_symlink"] = 0
+
+ bdist_inno.run(self, install_options)
+
+ def get_gdal_content(self):
+ '''
+ Return the list of files in the gdal directory of the Thuban installation
+ '''
+ gdal_files = []
+ for (dirpath, dnames, fnames) in os.walk('gdal'):
+ if len(fnames) > 0:
+ for file in fnames :
+ gdal_files.append(dirpath + os.sep + file)
+ return gdal_files
+
+class thuban_build_docs(Command):
+
+ """Command to generate documentation from source code."""
+
+ description = "Generate documentation."
+
+ user_options = []
+
+ def initialize_options(self): pass
+
+ def finalize_options(self): pass
+
+ def run(self, install_options = None):
+ self.spawn(["happydoc", "-d./Doc", "./Thuban"])
+
+class thuban_build_ext(build_ext):
+
+ """Extend the build_ext command with some Thuban specific options
+
+ --with-gdal, --without-gdal
+
+ Switch the optional GDAL support on/off. Default is On.
+
+ --use-wx-python-swig-hack
+
+ For performance reasons, Thuban access wxPython objects at the
+ C++ level so that it can directly call wxWidgets code from C++.
+ The normal and preferred way to do that is to use the API
+ defined in wxPython.h. Unfortunately, this header file is not
+ distributed with binary packages of wxPython on some platforms.
+ By using the --use-wx-python-swig-hack option you can activate a
+ way to access the C++ objects without wxPython.h. This relies
+ on internals of SWIG, so it might change with future wxPython
+ versions. Therefore, only use this option if the normal way
+ doesn't work for you.
+ """
+
+ user_options = build_ext.user_options[:]
+ user_options.extend([("with-gdal", None, "Include GDAL support."),
+ ("without-gdal", None, "Don't include GDAL support."),
+ ("use-wx-python-swig-hack", None,
+ "Use a hack to access wxPython objects at the C++ level"
+ "(use only when you absolutely can't use wxPython.h)")])
+
+ boolean_options = ["with-gdal", "use-wx-python-swig-hack"]
+ negative_opt = {'without-gdal' : 'with-gdal'}
+
+ def initialize_options(self):
+ self.with_gdal = True
+ self.use_wx_python_swig_hack = False
+ build_ext.initialize_options(self)
+
+ def finalize_options(self):
+ build_ext.finalize_options(self)
+ if self.with_gdal and include_gdal:
+ self.extensions.append(Extension("Lib.gdalwarp",
+ [ext_dir + "/thuban/gdalwarp.cpp"],
+ include_dirs = gdal_cs_params[CS_INCDIRS] +
+ [ext_dir + "/thuban/"],
+ define_macros = gdal_cs_params[CS_DEFS],
+ library_dirs = gdal_cs_params[CS_LIBDIRS],
+ libraries = gdal_cs_params[CS_LIBS]))
+ if self.use_wx_python_swig_hack:
+ wxproj_extension.define_macros.append(("USE_WX_PYTHON_SWIG_HACK",
+ None))
+
+ def run(self, install_options = None):
+ build_ext.run(self)
+
+#
+# Run the script
+#
+
+long_description = """\
+Thuban is a viewer for geographic data written in Python
+"""
+
+setup(name = "Thuban",
+ version = "1.2.0",
+ description = "Geographic data viewer",
+ long_description = long_description,
+ license = "GPL",
+ author = "Intevation GmbH",
+ author_email = "thuban at intevation.de",
+ url = "http://thuban.intevation.de/",
+
+ scripts = ["thuban.py"],
+ packages = ["Thuban", "Thuban.Lib", "Thuban.Model", "Thuban.UI",
+ "Extensions", "Extensions.gns2shp", "Extensions.wms",
+ "Extensions.importAPR", "Extensions.profiling",
+ "Extensions.svgexport", "Extensions.mouseposition",
+ "Extensions.bboxdump", "Extensions.ogr",
+ "Extensions.umn_mapserver"],
+ ext_modules = extensions,
+ py_modules = py_modules,
+ data_files = data_files,
+
+ # defaults for the install command
+ options = {"install":
+ # prefix defaults to python's prefix normally
+ {"prefix": prefix,
+ # make sure both libs and scripts are installed in the
+ # same directory.
+ "install_lib": "$base/lib/thuban",
+ "install_scripts": "$base/lib/thuban",
+ "install_data": "$base/lib/thuban",
+ # Don't print warning messages about the lib dir not
+ # being on Python's path. The libraries are Thuban
+ # specific and are installed just for Thuban. They'll
+ # be automatically on Python's path when Thuban is run
+ "warn_dir": 0,
+ },
+ "bdist_inno":
+ {"icons_entries": [InnoIconItem(".\\thuban.py",
+ "Start Thuban",
+ "{app}\\thuban.pyw")],
+ "license_file": "COPYING",
+ }
+ },
+ cmdclass = {"build_py": thuban_build_py,
+ "install_local": InstallLocal,
+ "install": ThubanInstall,
+ "bdist_rpm": thuban_bdist_rpm,
+ "bdist_inno": thuban_bdist_inno,
+ "data_dist": data_dist,
+ "build_docs": thuban_build_docs,
+ "build_ext": thuban_build_ext
+ })
+
+
Added: packages/thuban/branches/upstream/current/test/README
===================================================================
--- packages/thuban/branches/upstream/current/test/README 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/README 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,41 @@
+This directory contains the Thuban test suite.
+
+To run all tests run runtests.py:
+
+ $ python runtests.py
+
+To run individual tests, run one of the test_*.py scripts, e.g.:
+
+ $ python test_table.py -v
+
+
+The tests use the unittest module of the python standard library.
+
+Some of the tests expect the iceland sample data to be present in
+../Data and so may fail if you are working from a source archive
+unless you also add the data.
+
+Test for optional features should be automatically skipped when run on
+an installation where the feature is not available or the test can't be
+run for some other reason as may be the case with the postgis interface
+tests (see below). Skipped tests are marked with an S in the default
+brief output and are listed after all test have been run.
+
+The PostGIS tests require a PostGIS installation on the machine where
+the tests are run even though Thuban can use PostGIS database as long as
+psycopg is installed. The test will create their own database cluster in
+temp/postgis and start their own postmaster process, so the only
+requirement is that the software is installed and the various postgresql
+command line programs are on the PATH because they're executed as
+subprocesses to build the database cluster, start the postmaster, etc.
+
+E.g. Debian 4.0 (Etch) can have several PostGIS installations
+in parallel. So you can give the PATH to the one you want to test
+on the command line:
+
+ $ PATH=$PATH:/usr/lib/postgresql/8.1/bin/ python runtests.py
+
+
+$Revision: 2723 $
+$Source$
+$Id: README 2723 2007-02-20 10:22:54Z bernhard $
Added: packages/thuban/branches/upstream/current/test/localessupport.py
===================================================================
--- packages/thuban/branches/upstream/current/test/localessupport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/localessupport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,61 @@
+# Copyright (C) 2006 by Intevation GmbH
+# Author(s):
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Support code for setting locales."""
+
+__version__ = "$Revision: $"
+# $Id: xmlsupport.py 1683 2003-08-28 15:20:57Z bh $
+
+import locale
+from locale import LC_NUMERIC, getlocale, setlocale, localeconv
+
+_verbose = 0
+
+def setdecimalcommalocale():
+ """Find and set LC_NUMERIC locale that uses comma as decimal_point.
+
+ Return the previous locale to be able to set the previous LC_NUMERIC.
+ This can be "(None, None)" or None if none was found.
+ """
+
+ encodings = [".UTF-8", "@euro"]
+ locales = ["de_DE", "fr_FR", "fr_BE"]
+
+ oldlocale = getlocale(LC_NUMERIC)
+
+ tries = []
+ for l in locales:
+ for e in encodings:
+ tries.append(l + e)
+
+ for t in tries:
+ try:
+ if _verbose > 0:
+ print "trying", repr(t)
+ setlocale(LC_NUMERIC,t)
+ except locale.Error:
+ continue
+ break
+
+ # did we find one?
+ if localeconv()['decimal_point'] == ",":
+ return oldlocale
+
+ setlocale(LC_NUMERIC,oldlocale)
+ return None
+
+if __name__ == "__main__":
+ # test and print result
+ print "Searching for LC_NUMERIC locale with comma as decimal_point ..."
+ _verbose = 1
+ oldlocale = setdecimalcommalocale()
+ if oldlocale == None:
+ print "none found."
+ else:
+ print "found: ",
+ print getlocale(LC_NUMERIC)
+ setlocale(LC_NUMERIC,oldlocale)
Added: packages/thuban/branches/upstream/current/test/mockgeo.py
===================================================================
--- packages/thuban/branches/upstream/current/test/mockgeo.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/mockgeo.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,152 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Mock geometric/geographic objects"""
+
+from __future__ import generators
+
+__version__ = "$Revision: 1593 $"
+# $Source$
+# $Id: mockgeo.py 1593 2003-08-15 14:10:27Z bh $
+
+
+class SimpleShape:
+
+ def __init__(self, shapeid, points):
+ self.shapeid = shapeid
+ self.points = points
+
+ def Points(self):
+ return self.points
+
+ def ShapeID(self):
+ return self.shapeid
+
+ def RawData(self):
+ return self.points
+
+ def compute_bbox(self):
+ xs = []
+ ys = []
+ for part in self.Points():
+ for x, y in part:
+ xs.append(x)
+ ys.append(y)
+ return (min(xs), min(ys), max(xs), max(ys))
+
+
+class SimpleShapeStore:
+
+ """A simple shapestore object which holds its data in memory"""
+
+ def __init__(self, shapetype, shapes, table):
+ """Initialize the simple shapestore object.
+
+ The shapetype should be one of the predefined SHAPETYPE_*
+ constants. shapes is a list of shape definitions. Each
+ definitions is a list of lists of tuples as returned by the
+ Shape's Points() method. The table argument should be an object
+ implementing the table interface and contain with one row for
+ each shape.
+ """
+ self.shapetype = shapetype
+ self.shapes = shapes
+ self.table = table
+ assert table.NumRows() == len(shapes)
+
+ def ShapeType(self):
+ return self.shapetype
+
+ def Table(self):
+ return self.table
+
+ def NumShapes(self):
+ return len(self.shapes)
+
+ def Shape(self, index):
+ return SimpleShape(index, self.shapes[index])
+
+ def BoundingBox(self):
+ xs = []
+ ys = []
+ for shape in self.shapes:
+ for part in shape:
+ for x, y in part:
+ xs.append(x)
+ ys.append(y)
+ return (min(xs), min(ys), max(xs), max(ys))
+
+ def ShapesInRegion(self, bbox):
+ left, bottom, right, top = bbox
+ if left > right:
+ left, right = right, left
+ if bottom > top:
+ bottom, top = top, bottom
+ for i in xrange(len(self.shapes)):
+ shape = SimpleShape(i, self.shapes[i])
+ sleft, sbottom, sright, stop = shape.compute_bbox()
+ if (left <= sright and right >= sleft
+ and top >= sbottom and bottom <= stop):
+ yield shape
+
+ def AllShapes(self):
+ for i in xrange(len(self.shapes)):
+ yield SimpleShape(i, self.shapes[i])
+
+
+class AffineProjection:
+
+ """Projection-like object implemented with an affine transformation
+
+ The transformation matrix is defined by a list of six floats:
+
+ [m11, m21, m12, m22, v1, v2]
+
+ This list is essentially in the same form as used in PostScript.
+
+ This interpreted as the following transformation of (x, y):
+
+ / x \ / m11 m12 \ / x \ / v1 \
+ T * | | = | | | | + | |
+ \ y / \ m21 m22 / \ y / \ v2 /
+
+ or, in homogeneous coordinates:
+
+ / m11 m12 v1 \ / x \
+ | | | |
+ ^= | m21 m22 v2 | | y |
+ | | | |
+ \ 0 0 1 / \ 1 /
+
+ Obviously this is not a real geographic projection, but it's useful
+ in test cases because it's simple and the result is easily computed
+ in advance.
+ """
+
+ def __init__(self, coeff):
+ self.coeff = coeff
+
+ # determine the inverse transformation right away. We trust that
+ # an inverse exist for the transformations used in the Thuban
+ # test suite.
+ m11, m21, m12, m22, v1, v2 = coeff
+ det = float(m11 * m22 - m12 * m21)
+ n11 = m22 / det
+ n12 = -m12 / det
+ n21 = -m21 / det
+ n22 = m11 / det
+ self.inv = [n11, n21, n12, n22, -n11*v1 - n12*v2, -n21*v1 - n22*v2]
+
+ def _apply(self, matrix, x, y):
+ m11, m21, m12, m22, v1, v2 = matrix
+ return (m11 * x + m12 * y + v1), (m21 * x + m22 * y + v2)
+
+ def Forward(self, x, y):
+ return self._apply(self.coeff, x, y)
+
+ def Inverse(self, x, y):
+ return self._apply(self.inv, x, y)
Added: packages/thuban/branches/upstream/current/test/postgissupport.py
===================================================================
--- packages/thuban/branches/upstream/current/test/postgissupport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/postgissupport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,788 @@
+# Copyright (C) 2003, 2004, 2005, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Support module for tests that use a live PostGIS database"""
+
+__version__ = "$Revision: 2717 $"
+# $Source$
+# $Id: postgissupport.py 2717 2007-01-01 21:44:05Z bernhard $
+
+import sys
+import os
+import time
+import popen2
+import shutil
+import traceback
+import re
+
+import support
+
+try:
+ import psycopg
+except ImportError:
+ psycopg = None
+
+#
+# Helper code
+#
+
+def run_config_script(cmdline):
+ """Run command cmdline and return its stdout or none in case of errors"""
+ pipe = os.popen(cmdline)
+ result = pipe.read()
+ if pipe.close() is not None:
+ raise RuntimeError('Command %r failed' % cmdline)
+ return result
+
+def run_command(command, outfilename = None):
+ """Run command as a subprocess and send its stdout and stderr to outfile
+
+ The subprocess is run synchroneously so the function returns once
+ the subprocess has termninated. If the process' exit code is not
+ zero raise a RuntimeError.
+
+ If outfilename is None stdout and stderr are still captured but they
+ are ignored and not written to any file.
+ """
+ proc = popen2.Popen4(command)
+ proc.tochild.close()
+ output = proc.fromchild.read()
+ status = proc.wait()
+ if outfilename is not None:
+ outfile = open(outfilename, "w")
+ outfile.write(output)
+ outfile.close()
+ if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
+ if outfilename:
+ message = "see %s" % outfilename
+ else:
+ message = output
+ raise RuntimeError("command %r exited with code %d.\n%s"
+ % (command, status, message))
+
+
+def run_boolean_command(command):
+ """
+ Run command as a subprocess silently and return whether it ran successfully
+
+ Silently means that all output is captured and ignored. The exit
+ status is true if the command ran successfull, i.e. it terminated by
+ exiting and returned as zero exit code and false other wise
+ """
+ try:
+ run_command(command, None)
+ return 1
+ except RuntimeError:
+ pass
+ return 0
+
+
+#
+# PostgreSQL and database
+#
+
+_pg_ctl_command = "pg_ctl"
+_initdb_command = "initdb"
+# Example Values for Debian (upcomind Etch) postgresql-8.1
+# TODO: detect which values to use here.
+#_pg_ctl_command = "/usr/lib/postgresql/8.1/bin/pg_ctl"
+#_initdb_command = "/usr/lib/postgresql/8.1/bin/initdb"
+
+class PostgreSQLServer:
+
+ """A PostgreSQL server
+
+ Instances of this class represent a PostgreSQL server with postgis
+ extensions run explicitly for the test cases. Such a server has its
+ own database directory and its own directory for the unix sockets so
+ that it doesn't interfere with any other PostgreSQL server already
+ running on the system.
+ """
+
+ def __init__(self, dbdir, port, postgis_sql, socket_dir):
+ """Initialize the PostgreSQLServer object
+
+ Parameters:
+
+ dbdir -- The directory for the databases
+ port -- The port to use
+ postgis_sql -- The name of the file with the SQL statements to
+ initialize a database for postgis.
+ socket_dir -- The directory for the socket files.
+
+ When connecting to the database server use the port and host
+ instance variables.
+ """
+ self.dbdir = dbdir
+ self.port = port
+ self.postgis_sql = postgis_sql
+ self.socket_dir = socket_dir
+
+ # For the client side the socket directory can be used as the
+ # host if the name starts with a slash.
+ self.host = os.path.abspath(socket_dir)
+
+ # name and password for the admin and an unprivileged user
+ self.admin_name = "postgres"
+ self.admin_password = "postgres"
+ self.user_name = "observer"
+ self.user_password = "telescope"
+
+ # Map db names to db objects
+ self.known_dbs = {}
+
+ def createdb(self):
+ """Create the database in dbdir and start the server.
+
+ First check whether the dbdir already exists and if necessary
+ stop an already running postmaster and remove the dbdir
+ directory completely. Then create a new database cluster in the
+ dbdir and start a postmaster.
+ """
+ if os.path.isdir(self.dbdir):
+ if self.is_running():
+ self.shutdown()
+ shutil.rmtree(self.dbdir)
+ os.mkdir(self.dbdir)
+
+ run_command([_initdb_command, "-D", self.dbdir, "-U", self.admin_name],
+ os.path.join(self.dbdir, "initdb.log"))
+
+ extra_opts = "-p %d" % self.port
+ if self.socket_dir is not None:
+ extra_opts += " -k %s" % self.socket_dir
+ run_command([_pg_ctl_command, "-D", self.dbdir,
+ "-l", os.path.join(self.dbdir, "logfile"),
+ "-o", extra_opts, "start"],
+ os.path.join(self.dbdir, "pg_ctl-start.log"))
+ # the -w option of pg_ctl doesn't work properly when the port is
+ # not the default port, so we have to implement waiting for the
+ # server ourselves
+ self.wait_for_postmaster()
+
+ self.alter_user(self.admin_name, self.admin_password)
+ self.create_user(self.user_name, self.user_password)
+
+ def wait_for_postmaster(self):
+ """Return when the database server is running
+
+ Internal method to wait until the postmaster process has been
+ started and is ready for client connections.
+ """
+ max_count = 60
+ count = 0
+ while count < max_count:
+ try:
+ run_command(["psql", "-l", "-p", str(self.port),
+ "-h", self.host, "-U", self.admin_name],
+ os.path.join(self.dbdir, "psql-%d.log" % count))
+ except RuntimeError:
+ pass
+ except:
+ traceback.print_exc()
+ else:
+ break
+ time.sleep(0.5)
+ count += 1
+ else:
+ raise RuntimeError("postmaster didn't start")
+
+ def is_running(self):
+ """Return whether a postmaster process is running on self.dbdir
+
+ This method runs pg_ctl status on the dbdir and returns True if
+ that command succeeds and False otherwise.
+
+ Note that it is possible that this method returns true even if
+ the PostgreSQLServer instance has just been created and
+ createdb() has not been called yet. This can happen, for
+ instance, if the server has been started manually for debugging
+ purposes after a test suite run.
+ """
+ return run_boolean_command([_pg_ctl_command, "-D", self.dbdir, "status"])
+
+ def shutdown(self):
+ """Stop the postmaster running for self.dbdir"""
+ run_command([_pg_ctl_command, "-m", "fast", "-D", self.dbdir, "stop"],
+ os.path.join(self.dbdir, "pg_ctl-stop.log"))
+
+ def new_postgis_db(self, dbname, tables = None, reference_systems = None,
+ views = None):
+ """Create and return a new PostGISDatabase object using self as server
+ """
+ db = PostGISDatabase(self, self.postgis_sql, dbname, tables = tables,
+ reference_systems = reference_systems,
+ views = views)
+ db.initdb()
+ self.known_dbs[dbname] = db
+ return db
+
+ def get_static_data_db(self, dbname, tables, reference_systems, views):
+ """Return a PostGISDatabase for a database with the given static data
+
+ If no databasse of the name dbname exists, create a new one via
+ new_postgis_db and upload the data.
+
+ If a database of the name dbname already exists and uses the
+ indicated data, return that. If the already existing db uses
+ different data raise a value error.
+
+ If the database doesn't exist, create a new one via
+ self.new_postgis_db.
+
+ The parameters tables and reference_systems have the same
+ meaning as for new_postgis_db.
+ """
+ db = self.known_dbs.get(dbname)
+ if db is not None:
+ if db.has_data(tables, reference_systems, views):
+ return db
+ raise ValueError("PostGISDatabase named %r doesn't have tables %r"
+ % (dbname, tables))
+ return self.new_postgis_db(dbname, tables, reference_systems, views)
+
+ def get_default_static_data_db(self):
+ dbname = "PostGISStaticTests"
+ srids = [(1, "proj=longlat datum=WGS84")]
+ tables = [
+ # Direct copies of the shapefiles. The shapeids are exactly
+ # the same, except where changed with "gid_offset", of
+ # course. Note that the test implementation requires that
+ # all the landmard tables use an gid_offset of 1000.
+ ("landmarks", os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.shp"),
+ [("gid_offset", 1000)]),
+ ("political", os.path.join("..", "Data", "iceland",
+ "political.shp")),
+ ("roads_multi", os.path.join("..", "Data", "iceland",
+ "roads-line.shp")),
+
+ # same as roads-multi but using LINESTRING instead of
+ # MULTILINESTRING
+ ("roads", os.path.join("..", "Data", "iceland",
+ "roads-line.shp"),
+ [("force_wkt_type", "LINESTRING")]),
+
+ # The polygon data as a MULTIPOLYGON geometry type
+ ("political_multi", os.path.join("..", "Data", "iceland",
+ "political.shp"),
+ [("force_wkt_type", "MULTIPOLYGON")]),
+
+ # Copy of landmarks but using an srid != -1
+ ("landmarks_srid", os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.shp"),
+ [("gid_offset", 1000),
+ ("srid", 1)]),
+
+ # Copy of landmarks with a gid column called "point_id" instead
+ # of "gid" and using an srid != -1.
+ ("landmarks_point_id", os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.shp"),
+ [("gid_offset", 1000),
+ ("srid", 1),
+ ("gid_column", "point_id")]),
+ ]
+ views = [("v_landmarks", "SELECT * FROM landmarks_point_id")]
+ return self.get_static_data_db(dbname, tables, srids, views)
+
+ def connection_params(self, user):
+ """Return the connection parameters for the given user
+
+ The return value is a dictionary suitable as keyword argument
+ list to PostGISConnection. The user parameter may be either
+ 'admin' to connect as admin or 'user' to connect as an
+ unprivileged user.
+ """
+ return {"host": self.host, "port": self.port,
+ "user": getattr(self, user + "_name"),
+ "password": getattr(self, user + "_password")}
+
+ def connection_string(self, user):
+ """Return (part of) the connection string to pass to psycopg.connect
+
+ The string contains host, port, user and password. The user
+ parameter must be either 'admin' or 'user', as for
+ connection_params.
+ """
+ params = []
+ for key, value in self.connection_params(user).items():
+ # FIXME: this doesn't do quiting correctly but that
+ # shouldn't be much of a problem (people shouldn't be using
+ # single quotes in filenames anyway :) )
+ params.append("%s='%s'" % (key, value))
+ return " ".join(params)
+
+ def execute_sql(self, dbname, user, sql):
+ """Execute the sql statament and return a result for SELECT statements
+
+ The user parameter us used as in connection_params. The dbname
+ parameter must be the name of a database in the cluster. The
+ sql parameter is the SQL statement to execute as a string. If
+ the string starts with 'select' (matched case insensitively) the
+ first row of the result will be returned. Otherwise the return
+ value is None.
+ """
+ conn = psycopg.connect("dbname=%s " % dbname
+ + self.connection_string(user))
+ cursor = conn.cursor()
+ cursor.execute(sql)
+ if sql.lower().startswith("select"):
+ row = cursor.fetchone()
+ else:
+ row = None
+ conn.commit()
+ conn.close()
+ return row
+
+ def server_version(self):
+ """Return the server version as a tuple (major, minor, patch)
+
+ Each item in the tuple is an int.
+ """
+ result = self.execute_sql("template1", "admin", "SELECT version();")[0]
+ match = re.match(r"PostgreSQL (\d+\.\d+\.\d+)", result)
+ if match:
+ return tuple(map(int, match.group(1).split(".")))
+ else:
+ raise RutimeError("Cannot determine PostgreSQL server version"
+ " from %r" % result)
+
+ def require_authentication(self, required):
+ """Switch authentication requirements on or off
+
+ When started for the first time no passwords are required. Some
+ tests want to explicitly test whether Thuban's password
+ infrastructure works and switch password authentication on
+ explicitly. When switching it on, there should be a
+ corresponding call to switch it off again in the test case'
+ tearDown method or in a finally: block.
+ """
+ # Starting with PostgreSQL 7.3 the pg_hba.conf file has an
+ # additional column with a username. Query the server version
+ # and generate a file in the correct format.
+ if self.server_version() >= (7, 3):
+ user = "all"
+ else:
+ user = ""
+ if required:
+ contents = "local all %s password\n" % user
+ else:
+ contents = "local all %s trust\n" % user
+ f = open(os.path.join(self.dbdir, "pg_hba.conf"), "w")
+ f.write(contents)
+ f.close()
+ run_command([_pg_ctl_command, "-D", self.dbdir, "reload"],
+ os.path.join(self.dbdir, "pg_ctl-reload.log"))
+
+
+ def create_user(self, username, password):
+ """Create user username with password in the database"""
+ self.execute_sql("template1", "admin",
+ "CREATE USER %s PASSWORD '%s';" % (username,password))
+
+ def alter_user(self, username, password):
+ """Change the user username's password in the database"""
+ self.execute_sql("template1", "admin",
+ "ALTER USER %s PASSWORD '%s';" % (username,password))
+
+
+class PostGISDatabase:
+
+ """A PostGIS database in a PostgreSQLServer"""
+
+ def __init__(self, server, postgis_sql, dbname, tables = None,
+ reference_systems = (), views = None):
+ """Initialize the PostGISDatabase
+
+ Parameters:
+
+ server -- The PostgreSQLServer instance containing the
+ database
+
+ postgis_sql -- Filename of the sql file with the postgis
+ initialization code
+
+ dbname -- The name of the database
+
+ tables -- Optional description of tables to create in the
+ new database. If given it should be a list of
+ (tablename, shapefilename) pairs meaning that a table
+ tablename will be created with the contents of the given
+ shapefile or (tablename, shapefilename, extraargs)
+ triples. The extraargs should be a list of key, value
+ pairs to use as keyword arguments to upload_shapefile.
+
+ reference_systems -- Optional description of spatial
+ reference systems. If given, it should be a sequence of
+ (srid, params) pairs where srid is the srid defined by
+ the proj4 paramter string params. The srid can be given
+ as an extra parameter in the tables list.
+
+ views -- Optional description of views. If given it should
+ be a list of (viewname, select_stmt) pairs where
+ viewname is the name of the view to be created and
+ select_stmt is the select statement to use as the basis.
+ The views will be created after the tables and may refer
+ to them in the select_stmt.
+ """
+ self.server = server
+ self.postgis_sql = postgis_sql
+ self.dbname = dbname
+ self.tables = tables
+ self.views = views
+ if reference_systems:
+ self.reference_systems = reference_systems
+ else:
+ # Make sure that it's a sequence we can iterate over even if
+ # the parameter's None
+ self.reference_systems = ()
+
+ def initdb(self):
+ """Remove the old db directory and create and initialize a new database
+ """
+ run_command(["createdb", "-p", str(self.server.port),
+ "-h", self.server.host, "-U", self.server.admin_name,
+ self.dbname],
+ os.path.join(self.server.dbdir, "createdb.log"))
+ run_command(["createlang", "-p", str(self.server.port),
+ "-h", self.server.host, "-U", self.server.admin_name,
+ "plpgsql", self.dbname],
+ os.path.join(self.server.dbdir, "createlang.log"))
+ # for some reason psql doesn't exit with an error code if the
+ # file given as -f doesn't exist, so we check manually by trying
+ # to open it before we run psql
+ f = open(self.postgis_sql)
+ f.close()
+ del f
+ run_command(["psql", "-f", self.postgis_sql, "-d", self.dbname,
+ "-p", str(self.server.port), "-h", self.server.host,
+ "-U", self.server.admin_name],
+ os.path.join(self.server.dbdir, "psql.log"))
+
+ self.server.execute_sql(self.dbname, "admin",
+ "GRANT SELECT ON geometry_columns TO PUBLIC;")
+ self.server.execute_sql(self.dbname, "admin",
+ "GRANT SELECT ON spatial_ref_sys TO PUBLIC;")
+
+ for srid, params in self.reference_systems:
+ self.server.execute_sql(self.dbname, "admin",
+ "INSERT INTO spatial_ref_sys VALUES"
+ " (%d, '', %d, '', '%s');"
+ % (srid, srid, params))
+ if self.tables is not None:
+ def unpack(item):
+ extra = {"force_wkt_type": None, "gid_offset": 0,
+ "srid": -1}
+ if len(info) == 2:
+ tablename, shapefile = info
+ else:
+ tablename, shapefile, kw = info
+ for key, val in kw:
+ extra[key] = val
+ return tablename, shapefile, extra
+
+ for info in self.tables:
+ tablename, shapefile, kw = unpack(info)
+ upload_shapefile(shapefile, self, tablename, **kw)
+
+ if self.views is not None:
+ for viewname, select_stmt in self.views:
+ self.server.execute_sql(self.dbname, "admin",
+ "CREATE VIEW %s AS %s" % (viewname,
+ select_stmt))
+ self.server.execute_sql(self.dbname, "admin",
+ "GRANT SELECT ON %s TO PUBLIC;"
+ % viewname)
+
+ def has_data(self, tables, reference_systems, views):
+ return (self.tables == tables
+ and self.reference_systems == reference_systems
+ and self.views == views)
+
+
+def find_postgis_sql():
+ """Return the name of the postgis_sql file
+
+ A postgis installation usually has the postgis_sql file in
+ PostgreSQL's $datadir (i.e. the directory where PostgreSQL keeps
+ static files, not the directory containing the databases).
+ Unfortunately there's no way to determine the name of this directory
+ with pg_config so we assume here that it's
+ $bindir/../share/postgresql/.
+
+ Furthermore, different versions of postgis place the file in
+ slightly different locations or may even use different names. For
+ instance:
+
+ postgis 0.7.5 $datadir/contrib/postgis.sql
+ postgis 0.8.1 $datadir/postgis.sql
+ postgis 1.0.0-rc1 $datadir/lwpostgis.sql
+ postgis 1.0.0-rc4 $datadir/contrib/lwpostgis.sql
+
+ To support both versions, we look in both places and return the
+ first one found (looking under contrib first).
+
+ Debian (umcoming Etch) can do several version of postgresql
+ and thus has changed the paths. We try one location
+ in datadir2 only for Debian Etch postgresql-8.1.
+
+ If the file is not found the return value is None.
+ """
+ bindir = run_config_script("pg_config --bindir").strip()
+ datadir = os.path.join(bindir, "..", "share", "postgresql")
+ datadir2 = os.path.join("/", "usr", "share", "postgresql-8.1-postgis")
+
+ for filename in [os.path.join(datadir, "contrib", "postgis.sql"),
+ os.path.join(datadir, "postgis.sql"),
+ os.path.join(datadir, "lwpostgis.sql"),
+ os.path.join(datadir, "contrib", "lwpostgis.sql"),
+ os.path.join(datadir2, "lwpostgis.sql") \
+ ]:
+ if os.path.exists(filename):
+ return filename
+
+
+_postgres_server = None
+def get_test_server():
+ """Return the test database server object.
+
+ If it doesn't exist yet, create it first.
+
+ The server will use the directory postgis under the temp dir (as
+ defined by support.create_temp_dir()) for the database cluster.
+ Sockets will be created in tempdir.
+ """
+ global _postgres_server
+ if _postgres_server is None:
+ tempdir = support.create_temp_dir()
+ dbdir = os.path.join(tempdir, "postgis")
+ socket_dir = tempdir
+
+ _postgres_server = PostgreSQLServer(dbdir, 6543, find_postgis_sql(),
+ socket_dir = socket_dir)
+ _postgres_server.createdb()
+
+ return _postgres_server
+
+def shutdown_test_server():
+ """Shutdown the test server if it is running"""
+ global _postgres_server
+ if _postgres_server is not None:
+ _postgres_server.shutdown()
+ _postgres_server = None
+
+
+def reason_for_not_running_tests():
+ """
+ Determine whether postgis tests can be run and return a reason they can't
+
+ There's no fool-proof way to reliably determine this short of
+ actually running the tests but we try the following here:
+
+ - test whether pg_ctl --help can be run successfully
+ - test whether the postgis_sql can be opened
+ The name of the postgis_sql file is determined by find_postgis_sql()
+ - psycopg can be imported successfully.
+ """
+ # run_command currently uses Popen4 which is not available under
+ # Windows, for example.
+ if not hasattr(popen2, "Popen4"):
+ return "Can't run PostGIS test because popen2.Popen4 does not exist"
+
+ try:
+ run_command([_pg_ctl_command, "--help"], None)
+ except RuntimeError:
+ return "Can't run PostGIS tests because pg_ctl fails"
+
+ try:
+ postgis_sql = find_postgis_sql()
+ except:
+ return "Can't run PostGIS tests because postgis.sql can't be found"
+
+ try:
+ f = open(postgis_sql)
+ f.close()
+ except:
+ return "Can't run PostGIS tests because postgis.sql can't be opened"
+
+ # The test for psycopg was already done when this module was
+ # imported so we only have to check whether it was successful
+ if psycopg is None:
+ return "Can't run PostGIS tests because psycopg can't be imported"
+
+ return ""
+
+
+_cannot_run_postgis_tests = None
+def skip_if_no_postgis():
+ global _cannot_run_postgis_tests
+ if _cannot_run_postgis_tests is None:
+ _cannot_run_postgis_tests = reason_for_not_running_tests()
+ if _cannot_run_postgis_tests:
+ raise support.SkipTest(_cannot_run_postgis_tests)
+
+def skip_if_addgeometrycolumn_does_not_use_quote_ident():
+ """Skip a test if the AddGeometryColumn function doesn't use quote_ident
+
+ If the AddGeometryColumn function doesn't use quote_ident it doesn't
+ support unusual table or column names properly, that is, it will
+ fail with errors for names that contain spaces or double quotes.
+
+ The test performed by this function is a bit simplistic because it
+ only tests whether the string 'quote_ident' occurs anywhere in the
+ postgis.sql file. This will hopefully work because when this was
+ fixed in postgis CVS AddGeometryColumn was the first function to use
+ quote_ident.
+ """
+ f = file(find_postgis_sql())
+ content = f.read()
+ f.close()
+ if content.find("quote_ident") < 0:
+ raise support.SkipTest("AddGeometryColumn doesn't use quote_ident")
+
+def coords_to_point(coords):
+ """Return string with a WKT representation of the point in coords"""
+ x, y = coords[0]
+ return "POINT(%r %r)" % (x, y)
+
+def coords_to_polygon(coords):
+ """Return string with a WKT representation of the polygon in coords"""
+ poly = []
+ for ring in coords:
+ poly.append(", ".join(["%r %r" % p for p in ring]))
+ return "POLYGON((%s))" % "), (".join(poly)
+
+def coords_to_linestring(coords):
+ """Return string with a LINESTRING WKT representation of coords"""
+ if len(coords) > 1:
+ raise ValueError("A LINESTRING can only have one arc")
+ return "LINESTRING(%s)" % ", ".join(["%r %r" % p for p in coords[0]])
+
+def coords_to_multilinestring(coords):
+ """Return string with a MULTILINESTRING WKT representation of coords"""
+ poly = []
+ for ring in coords:
+ poly.append(", ".join(["%r %r" % p for p in ring]))
+ return "MULTILINESTRING((%s))" % "), (".join(poly)
+
+def coords_to_multipolygon(coords):
+ """Return string with a WKT representation of the polygon in coords"""
+ poly = []
+ for ring in coords:
+ poly.append(", ".join(["%r %r" % p for p in ring]))
+ return "MULTIPOLYGON(((%s)))" % ")), ((".join(poly)
+
+wkt_converter = {
+ "POINT": coords_to_point,
+ "LINESTRING": coords_to_linestring,
+ "MULTILINESTRING": coords_to_multilinestring,
+ "POLYGON": coords_to_polygon,
+ "MULTIPOLYGON": coords_to_multipolygon,
+ }
+
+def upload_shapefile(filename, db, tablename, force_wkt_type = None,
+ gid_offset = 0, gid_column = "gid", srid = -1):
+ """Upload a shapefile into a new database table
+
+ Parameters:
+
+ filename -- The name of the shapefile
+
+ db -- The PostGISDatabase instance representing the database
+
+ tablename -- The name of the table to create and into which the data
+ is to be inserted
+
+ force_wkt_type -- If given and not None, this is used as the WKT
+ geometry type to use instead of the default that would
+ be chosen based on the type of the shapefile
+
+ gid_offset -- A number to add to the shapeid to get the value for
+ the gid column (default 0)
+
+ gid_column -- The name of the column with the shape ids. Default
+ 'gid'. If None, no gid column will be created. The
+ name is directly used in SQL statements, so if it
+ contains unusualy characters the caller should provide
+ a suitable quoted string.
+
+ srid -- The srid of the spatial references system used by the table
+ and the data
+
+ The tables will be explicitely created WITH OIDS. This has been
+ default for PostgreSQL <8.0 and some tests relied on it (end of 2006).
+ """
+ import dbflib, shapelib
+
+ # We build this map here because we need shapelib which can only be
+ # imported after support.initthuban has been called which we can't
+ # easily do in this module because it's imported by support.
+ shp_to_wkt = {
+ shapelib.SHPT_POINT: "POINT",
+ shapelib.SHPT_ARC: "MULTILINESTRING",
+ shapelib.SHPT_POLYGON: "POLYGON",
+ }
+
+ server = db.server
+ dbname = db.dbname
+ conn = psycopg.connect("dbname=%s " % dbname
+ + db.server.connection_string("admin"))
+ cursor = conn.cursor()
+
+ shp = shapelib.ShapeFile(filename)
+ dbf = dbflib.DBFFile(filename)
+ typemap = {dbflib.FTString: "VARCHAR",
+ dbflib.FTInteger: "INTEGER",
+ dbflib.FTDouble: "DOUBLE PRECISION"}
+
+ insert_formats = []
+ if gid_column:
+ insert_formats.append("%(gid)s")
+
+ fields = []
+ fields_decl = []
+ if gid_column:
+ fields.append(gid_column)
+ fields_decl.append("%s INT" % gid_column)
+ for i in range(dbf.field_count()):
+ ftype, name, width, prec = dbf.field_info(i)
+ fields.append(name)
+ fields_decl.append("%s %s" % (name, typemap[ftype]))
+ insert_formats.append("%%(%s)s" % name)
+ stmt = "CREATE TABLE %s (\n %s\n) WITH OIDS ;" % (tablename,
+ ",\n ".join(fields_decl))
+ cursor.execute(stmt)
+ #print stmt
+
+ numshapes, shapetype, mins, maxs = shp.info()
+ wkttype = shp_to_wkt[shapetype]
+ if force_wkt_type:
+ wkttype = force_wkt_type
+ convert = wkt_converter[wkttype]
+
+ cursor.execute("select AddGeometryColumn('%(dbname)s',"
+ "'%(tablename)s', 'the_geom', %(srid)d, '%(wkttype)s', 2);"
+ % locals())
+ fields.append("the_geom")
+ insert_formats.append("GeometryFromText(%(the_geom)s, %(srid)d)")
+
+ insert = ("INSERT INTO %s (%s) VALUES (%s)"
+ % (tablename, ", ".join(fields), ", ".join(insert_formats)))
+
+ for i in range(numshapes):
+ data = dbf.read_record(i)
+ data["tablename"] = tablename
+ if gid_column:
+ data["gid"] = i + gid_offset
+ data["srid"] = srid
+ data["the_geom"] = convert(shp.read_object(i).vertices())
+ #print insert % data
+ cursor.execute(insert, data)
+
+ cursor.execute("GRANT SELECT ON %s TO PUBLIC;" % tablename)
+
+ conn.commit()
Added: packages/thuban/branches/upstream/current/test/runtests.py
===================================================================
--- packages/thuban/branches/upstream/current/test/runtests.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/runtests.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,115 @@
+# Copyright (c) 2002, 2003, 2004, 2005, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Main entry point for the Thuban test suite.
+
+Just run this file as a python script to execute all tests
+"""
+
+__version__ = "$Revision: 2705 $"
+# $Source$
+# $Id: runtests.py 2705 2006-09-24 18:55:30Z bernhard $
+
+import os
+
+# It should be possible to run the Thuban testsuite without an X
+# connection, so we remove the DISPLAY environment variable which should
+# lead to an error if the wxGTK module is imported accidentally. The
+# DISPLAY variable is not always set so we catch and ignore the KeyError
+try:
+ del os.environ["DISPLAY"]
+except KeyError:
+ pass
+
+import sys
+import warnings
+import unittest
+import getopt
+
+import support
+support.initthuban()
+import Thuban.Lib.connector
+
+def find_test_modules(dirname, package = None):
+ """Return a list the names of the test modules in the directory dirname
+
+ The return value is a list of names that can be passed to
+ unittest.defaultTestLoader.loadTestsFromNames. Each name of the
+ list is the name of a pure python module, one for each file in
+ dirname that starts with 'test'.
+
+ The optional parameter package should be the name of the python
+ package whose directory is dirname. If package is given all names
+ in the returned list will be prefixed with package and a dot.
+ """
+ if package:
+ prefix = package + "."
+ else:
+ prefix = ""
+
+ return [prefix + name[:-3]
+ for name in os.listdir(dirname)
+ if name[:4] == "test" and name[-3:] == ".py"]
+
+
+def main():
+ """Run all the tests in the Thuban test suite"""
+
+ # Turn Thuban's deprecation warnings into errors so they're caught
+ # by the tests
+ #
+ # Maintenance: Keep a warning filter until the backwards
+ # compatibility code is removed at which time using the old
+ # interfaces should lead to other errors anyway.
+
+ # The layer attributes table, shapetable, shapefile and filename are
+ # deprecated.
+ warnings.filterwarnings("error", "The Layer attribute.*is deprecated",
+ DeprecationWarning)
+
+ verbosity = 1
+
+ opts, args = getopt.getopt(sys.argv[1:], 'v',
+ ['verbose', 'setdecimalcommalocale', "internal-encoding="])
+ for optchar, value in opts:
+ if optchar in ("-v", "--verbose"):
+ verbosity = 2
+ elif optchar == "--internal-encoding":
+ Thuban.set_internal_encoding(value)
+ elif optchar == "--setdecimalcommalocale":
+ import localessupport
+ oldlocale = localessupport.setdecimalcommalocale()
+ if oldlocale == None:
+ print>>sys.stderr, "Did not find a locale with comma."
+ else:
+ print>>sys.stderr, "Unknown option", optchar
+
+ # Build the list of test names. If names were given on the command
+ # line, run exactly those. Othwerwise build a default list of
+ # names.
+ if args:
+ names = args
+ else:
+ # All Python files starting with 'test' in the current directory
+ # and some directories in Extensions contain test cases.
+ # FIXME: It should be possible to run runtests.py even when not in
+ # the test directory
+ names = find_test_modules(".")
+ names += find_test_modules("../Extensions/svgexport/test",
+ "Extensions.svgexport.test")
+ names += find_test_modules("../Extensions/ogr/test",
+ "Extensions.ogr.test")
+ suite = unittest.defaultTestLoader.loadTestsFromNames(names)
+ runner = support.ThubanTestRunner(verbosity = verbosity)
+ result = support.execute_as_testsuite(runner.run, suite)
+
+ sys.exit(not result.wasSuccessful())
+
+
+if __name__ == "__main__":
+ main()
Added: packages/thuban/branches/upstream/current/test/support.py
===================================================================
--- packages/thuban/branches/upstream/current/test/support.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/support.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,385 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Support classes and function for the test suite
+"""
+
+__version__ = "$Revision: 2642 $"
+# $Source$
+# $Id: support.py 2642 2005-07-01 20:49:04Z bh $
+
+import os, sys
+import unittest
+import traceback
+
+import postgissupport
+
+
+def thuban_dir():
+ """Return the directory containing the Thuban package"""
+ thisdir = os.path.dirname(__file__)
+ return os.path.join(thisdir, os.pardir)
+
+def resource_dir():
+ return os.path.join(thuban_dir(), "Resources")
+
+def add_thuban_dir_to_path():
+ """Insert the Thuban directory at the beginning of the python path.
+
+ If it's already part of the path, remove later occurrences.
+ """
+ dir = thuban_dir()
+ while 1:
+ try:
+ sys.path.remove(dir)
+ except ValueError:
+ break
+ sys.path.insert(0, dir)
+
+
+_initthuban_done = 0
+def initthuban():
+ """Initialize the interpreter for using Thuban modules
+ """
+ global _initthuban_done
+ if not _initthuban_done:
+ # Thuban uses gettext to translate some strings. Some of these
+ # strings are tested for equality in some test cases. So we
+ # unset any LANG environment setting to make sure only the
+ # untranslated messages are used.
+ try:
+ del os.environ["LANG"]
+ except KeyError:
+ pass
+ add_thuban_dir_to_path()
+ import thubaninit
+
+ # Install a dummy translation function so that importing
+ # Thuban.UI doesn't install a wx specific one for which would
+ # need to import wxPython
+ import Thuban
+ Thuban.install_translation_function(lambda s: s)
+
+ # For the time being the default encoding in the test suite is
+ # latin 1. This is mostly for historical reasons. Other
+ # encodings can be specified as an argument for runtests.py.
+ Thuban.set_internal_encoding("latin-1")
+
+ _initthuban_done = 1
+
+
+#
+# Special test runner and result that support skipping tests
+#
+
+class SkipTest(Exception):
+ """Exception to raise in tests that are skipped for some reason
+
+ For instance, since gdal support is optional, test cases that
+ require gdal raise this exception to indicate that they are skipped.
+ Skipped is different from failure or error in that it is expected
+ under certain circumstances.
+ """
+
+class ThubanTestResult(unittest._TextTestResult):
+
+ def __init__(self, stream, descriptions, verbosity):
+ unittest._TextTestResult.__init__(self, stream, descriptions,
+ verbosity)
+ self.skipped_tests = {}
+
+ def add_skipped_test(self, test, exc):
+ reason = str(exc)
+ self.skipped_tests.setdefault(reason, []).append(test)
+
+ def count_skipped(self):
+ sum = 0
+ for tests in self.skipped_tests.values():
+ sum += len(tests)
+ return sum
+
+ def addError(self, test, err):
+ """Extend inherited method to handle SkipTest exceptions specially
+ """
+ #print "addError", test, err
+ if isinstance(err[1], SkipTest):
+ self.add_skipped_test(test, err[1])
+ if self.showAll:
+ self.stream.writeln("skipped")
+ elif self.dots:
+ self.stream.write('S')
+ else:
+ unittest._TextTestResult.addError(self, test, err)
+
+ def printErrors(self):
+ if self.skipped_tests:
+ if self.dots or self.showAll:
+ self.stream.writeln()
+ self.stream.writeln("Skipped tests:")
+ for reason, tests in self.skipped_tests.items():
+ self.stream.writeln(" %s:" % reason)
+ for test in tests:
+ self.stream.writeln(" " + test.id())
+ unittest._TextTestResult.printErrors(self)
+
+ def getDescription(self, test):
+ return test.id()
+
+
+class ThubanTestRunner(unittest.TextTestRunner):
+
+ def _makeResult(self):
+ return ThubanTestResult(self.stream, self.descriptions, self.verbosity)
+
+ def run(self, test):
+ result = unittest.TextTestRunner.run(self, test)
+ self.stream.writeln("skipped = %d" % result.count_skipped())
+ return result
+
+
+class ThubanTestProgram(unittest.TestProgram):
+
+ def runTests(self):
+ """Extend inherited method so that we use a ThubanTestRunner"""
+ self.testRunner = ThubanTestRunner(verbosity = self.verbosity)
+ unittest.TestProgram.runTests(self)
+
+
+def execute_as_testsuite(callable, *args, **kw):
+ """Call callable with args as if it were the entry point to the test suite
+
+ Return watever callable returns.
+
+ This is a helper function for run_tests and runtests.py. Call
+ callable in a try-finally block and run some cleanup and print some
+ additional information in the finally block.
+
+ The additionaly information include:
+
+ - A list of uncollected objects (after an explicit garbage
+ collector call)
+
+ - any unsubscribed messages
+ """
+ try:
+ return callable(*args, **kw)
+ finally:
+ # This has to be in a finally clause because unittest.main()
+ # ends with a sys.exit to make sure that the process exits with
+ # an appropriate exit code
+
+ # Shutdown the postgis server if it's running
+ try:
+ postgissupport.shutdown_test_server()
+ except:
+ traceback.print_exc()
+
+ # Print additional information
+ print_additional_summary()
+
+def run_tests():
+ """Frontend for unittest.main that prints some additional debug information
+
+ After calling unittest.main, run the garbage collector and print
+ uncollected objects. Also print any un-unsubscribed messages.
+ """
+ execute_as_testsuite(ThubanTestProgram)
+
+
+def print_additional_summary():
+ """Print some additional summary information after tests have been run"""
+ print_garbage_information()
+ import xmlsupport
+ xmlsupport.print_summary_message()
+
+def print_garbage_information():
+ """Print information about things that haven't been cleaned up.
+
+ Run the garbage collector and print uncollected objects. Also print
+ any un-unsubscribed messages.
+ """
+ # this function may be called indirectly from test cases that test
+ # test support modules which do not use anything from thuban itself,
+ # so we call initthuban so that we can import the connector module
+ initthuban()
+ import gc, Thuban.Lib.connector
+ gc.collect()
+ if gc.garbage:
+ print
+ print "There are %d uncollected objects:" % len(gc.garbage)
+ print gc.garbage
+ Thuban.Lib.connector._the_connector.print_connections()
+
+#
+
+def create_temp_dir():
+ """Create a temporary directory and return its name.
+
+ The temporary directory is always called temp and is created in the
+ directory where support module is located.
+
+ If the temp directory already exists, just return the name.
+ """
+ name = os.path.abspath(os.path.join(os.path.dirname(__file__), "temp"))
+
+ # if the directory already exists, we're done
+ if os.path.isdir(name):
+ return name
+
+ # create the directory
+ os.mkdir(name)
+ return name
+
+
+class FileTestMixin:
+
+ """Mixin class for tests that use files in the temporary directory
+ """
+
+ def temp_file_name(self, basename):
+ """Return the full name of the file named basename in the temp. dir"""
+ return os.path.join(create_temp_dir(), basename)
+
+ def temp_dir(self):
+ """Return the name of the directory for the temporary files"""
+ return create_temp_dir()
+
+
+
+class FileLoadTestCase(unittest.TestCase, FileTestMixin):
+
+ """Base class for test case that test loading files.
+
+ This base class provides some common infrastructure for testing the
+ reading of files.
+
+ Each test case should be its own class derived from this one. There
+ is one file associated with each class. The contents are defined by
+ the file_contents class attribute and its name by the filename
+ method.
+
+ Derived classes usually only have to provide appropriate values for
+ the file_contents and file_extension class attributes.
+ """
+
+ file_contents = None
+ file_extension = ""
+
+ def filename(self):
+ """Return the name of the test file to use.
+
+ The default implementation simply calls self.temp_file_name with
+ a basename derived from the class name by stripping off a
+ leading 'test_' and appending self.file_extension.
+ """
+ name = self.__class__.__name__
+ if name.startswith("test_"):
+ name = name[5:]
+ return self.temp_file_name(name + self.file_extension)
+
+ def setUp(self):
+ """Create the volatile file for the test.
+
+ Write self.contents (which should be a string) to the file named
+ by self.filename().
+ """
+ filename = self.filename()
+ file = open(filename, "w")
+ file.write(self.file_contents)
+ file.close()
+
+
+class FloatComparisonMixin:
+
+ """
+ Mixin class for tests comparing floating point numbers.
+
+ This class provides a few methods for testing floating point
+ operations.
+ """
+
+ fp_epsilon = 1e-6
+ fp_inf = float('1e1000') # FIXME: hack for infinite
+
+ def assertFloatEqual(self, test, value, epsilon = None):
+ """Assert equality of test and value with some tolerance.
+
+ Assert that the absolute difference between test and value is
+ less than self.fp_epsilon.
+ """
+ if epsilon is None:
+ epsilon = self.fp_epsilon
+ if abs(test) == self.fp_inf:
+ self.assertEqual(test, value)
+ else:
+ self.assert_(epsilon > abs(test - value),
+ "abs(%g - %g) >= %g" % (test, value, epsilon))
+
+ def assertFloatSeqEqual(self, test, value, epsilon = None):
+ """Assert equality of the sequences test and value with some tolerance.
+
+ Assert that the absolute difference between each corresponding
+ value in test and value is less than the optional parameter
+ epsilon. If epsilon is not given use self.fp_epsilon.
+ """
+ self.assertEquals(len(test), len(value))
+ for i in range(len(test)):
+ self.assertFloatEqual(test[i], value[i], epsilon)
+
+ def assertPointListEquals(self, test, value):
+ """Assert equality of two lists of lists of tuples of float
+
+ This assertion is usually used to compare the geometry of shapes
+ as returned by a Shape object's Points() method, hence the name.
+ """
+ for i in range(len(test)):
+ self.assertEquals(len(test[i]), len(value[i]))
+ for j in range(len(test[i])):
+ self.assertFloatSeqEqual(test[i][j], value[i][j])
+
+
+class SubscriberMixin:
+
+ """Mixin class for tests for messages sent through the Connector
+
+ The SubscriberMixin has some methods that can be used as subscribers
+ of events that when called append information about the message into
+ a list of messages received.
+
+ A derived class should call the clear_messages() method in both its
+ setUp and tearDown methods to clear the list of messages received.
+ """
+
+ def clear_messages(self):
+ """Clear the list of received messages.
+
+ Call this at least in the tests setUp and tearDown methods. It's
+ important to do it in tearDown too because otherwise there may
+ be cyclic references.
+ """
+ self.received_messages = []
+
+ def subscribe_no_params(self):
+ """Method for subscriptions without parameters.
+
+ Add an empty tuple to the list of received messages.
+ """
+ self.received_messages.append(())
+
+ def subscribe_with_params(self, *args):
+ """Method for subscriptions with parameters.
+
+ Append the tuple will all arguments to this function (except for
+ the self argument) to the list of received messages.
+ """
+ self.received_messages.append(args)
+
+ def check_messages(self, messages):
+ """Check whether the messages received match the list messages"""
+ self.assertEquals(messages, self.received_messages)
+
Added: packages/thuban/branches/upstream/current/test/test_base.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_base.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_base.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,160 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the TitledObject and Modifiable
+"""
+
+__version__ = "$Revision: 1123 $"
+# $Source$
+# $Id: test_base.py 1123 2003-06-02 14:10:00Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.base import TitledObject, Modifiable
+from Thuban.Model.messages import TITLE_CHANGED, CHANGED
+
+SOMETHING_ELSE = "SOMETHING_ELSE"
+
+class SomeTitledObject(TitledObject, Modifiable):
+
+ """TitledObject for test purposes.
+
+ TitledObject is not used directly. It's a mixin to be used together
+ with Modifiable.
+ """
+
+class SomeModifiable(Modifiable):
+
+ """Modifiable for test purposes.
+
+ Modifiable is intended to be used as a base class for classes that
+ need to inform other classes when they change and that have to keep
+ track of whether they have changed. Thus we use a derived class for
+ testing that provides some methods that simulate modificatios.
+ """
+
+ def do_something(self):
+ """Call self.changed without parameters"""
+ self.changed()
+
+ def do_something_else(self):
+ """Call self.changed with a message parameter"""
+ self.changed(SOMETHING_ELSE)
+
+
+class SubscriberTest(unittest.TestCase, support.SubscriberMixin):
+
+ """Base class for test cases that use SubscriberMixin.
+
+ Just provide the default implementations of setUp and tearDown.
+ """
+
+ def setUp(self):
+ """Clear the list of received messages"""
+ self.clear_messages()
+
+ def tearDown(self):
+ """Clear the list of received messages"""
+ self.clear_messages()
+
+
+class TestTitledObject(SubscriberTest):
+
+ """Test cases for TitledObject"""
+
+ def test_titled_object(self):
+ """Test TitledObject"""
+ titled = SomeTitledObject("Some Title")
+ titled.Subscribe(TITLE_CHANGED,
+ self.subscribe_with_params, TITLE_CHANGED)
+
+ self.assertEquals(titled.Title(), "Some Title")
+
+ titled.SetTitle("New Title")
+ self.assertEquals(titled.Title(), "New Title")
+
+ self.check_messages([(titled, TITLE_CHANGED)])
+
+
+class TestModifiable(SubscriberTest):
+
+ """Test cases for Modifiable"""
+
+ def setUp(self):
+ """Extend the inherited method to create a Modifiable instance.
+
+ Bind the Modifiable instance (actually an instance of
+ SomeModifiable) to self.modifiable and subscribe to its CHANGED
+ and SOMETHING_ELSE channels.
+ """
+ SubscriberTest.setUp(self)
+ self.modifiable = SomeModifiable()
+ self.modifiable.Subscribe(CHANGED, self.subscribe_with_params, CHANGED)
+ self.modifiable.Subscribe(SOMETHING_ELSE,
+ self.subscribe_with_params, SOMETHING_ELSE)
+
+ def tearDown(self):
+ """Extend the inherited method to explicitly destroy self.modifiable.
+ """
+ self.modifiable.Destroy()
+ SubscriberTest.tearDown(self)
+
+ def test_initial_state(self):
+ """Test Modifiable initial state"""
+ # initially a modifiable is unmodified
+ self.failIf(self.modifiable.WasModified())
+ # this test should not have resulted in any messages
+ self.check_messages([])
+
+ def test_silent_change(self):
+ """Test Modifiable method which doesn't issue messages"""
+ self.modifiable.do_something()
+ # Now it should be modified and we should not have received any
+ # message
+ self.assert_(self.modifiable.WasModified())
+ self.check_messages([])
+
+ def test_unset_modified(self):
+ """Test Modifiable.UnsetModified.
+
+ Test whether the UnsetModified does in fact clear the modified
+ flag and whether it issues a CHANGED message if it changes the
+ modified flag from true to false.
+ """
+ # We start with an unmodified object, so when we call
+ # UnsetModified now it shouldn't result in any message.
+ self.modifiable.UnsetModified()
+ self.check_messages([])
+ self.failIf(self.modifiable.WasModified())
+
+ # Call a method that modifies the object silently.
+ self.modifiable.do_something()
+ self.check_messages([])
+ self.assert_(self.modifiable.WasModified())
+
+ # when we now call UnsetModified it should result in a CHANGED
+ # message
+ self.modifiable.UnsetModified()
+ self.check_messages([(CHANGED,)])
+ self.failIf(self.modifiable.WasModified())
+
+ def test_issuing_change(self):
+ """Test Modifiable method that issues messages"""
+ self.modifiable.do_something_else()
+ # Now it should be modified and we should have received a
+ # CHANGED message
+ self.check_messages([(SOMETHING_ELSE,)])
+ self.assert_(self.modifiable.WasModified())
+
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_baserenderer.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_baserenderer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_baserenderer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,597 @@
+# Copyright (C) 2003, 2005, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test Thuban.Model.baserenderer"""
+
+__version__ = "$Revision: 2712 $"
+# $Source$
+# $Id: test_baserenderer.py 2712 2006-10-15 23:27:05Z bernhard $
+
+import os
+import binascii
+import unittest
+import locale
+
+import localessupport
+from mockgeo import SimpleShapeStore
+import support
+support.initthuban()
+
+from Thuban.Model.color import Transparent, Color
+from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
+from Thuban.Model.map import Map
+from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
+from Thuban.Model.table import MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
+from Thuban.Model.classification import ClassGroupSingleton
+import Thuban.Model.resource
+
+
+from Thuban.UI.baserenderer import BaseRenderer, \
+ add_renderer_extension, init_renderer_extensions
+
+if Thuban.Model.resource.has_gdal_support():
+ from gdalwarp import ProjectRasterFile
+
+class MockDC:
+
+ def __init__(self, size = None):
+ self.calls = []
+ self.size = size
+
+ def GetSizeTuple(self):
+ return self.size
+
+ def __getattr__(self, attr):
+ def method(*args):
+ self.calls.append((attr,) + args)
+ return method
+
+class P:
+
+ """A simple point"""
+
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+ def __eq__(self, other):
+ return self.x == other.x and self.y == other.y
+
+ def __ne__(self, other):
+ return self.x != other.x and self.y != other.y
+
+ def __repr__(self):
+ return "P(%r, %r)" % (self.x, self.y)
+
+
+class SimpleRenderer(BaseRenderer):
+
+ TRANSPARENT_PEN = ("pen", Transparent)
+ TRANSPARENT_BRUSH = ("brush", Transparent)
+
+ def make_point(self, x, y):
+ return P(x, y)
+
+ def tools_for_property(self, prop):
+ fill = prop.GetFill()
+ brush = ("brush", fill)
+
+ stroke = prop.GetLineColor()
+ stroke_width = prop.GetLineWidth()
+ if stroke is Transparent:
+ pen = ("pen", Transparent)
+ else:
+ pen = ("pen", stroke, stroke_width)
+
+ return pen, brush
+
+ def label_font(self):
+ return "label font"
+
+ def draw_raster_data(self, x, y, data, format='BMP', opacity=1.0):
+ self.raster_data = data
+ self.raster_format = format
+
+ def projected_raster_layer(self, layer, srcProj, dstProj, extents,
+ resolution, dimensions, options):
+
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+ #print srcProj, dstProj,extents, resolution, dimensions, options
+
+ return ProjectRasterFile(layer.GetImageFilename(),
+ srcProj, dstProj,
+ extents, resolution, dimensions,
+ options)
+
+class MockProjection:
+
+ """Objects that look like projections but simply apply non-uniform scalings
+ """
+
+ def __init__(self, xscale, yscale):
+ self.xscale = float(xscale)
+ self.yscale = float(yscale)
+
+ def Forward(self, x, y):
+ return (x * self.xscale, y * self.yscale)
+
+ def Inverse(self, x, y):
+ return (x / self.xscale, y / self.yscale)
+
+
+class TestBaseRenderer(unittest.TestCase):
+
+ def setUp(self):
+ """Set self.to_destroy to an empty list
+
+ Tests should put all objects whose Destroy should be called at
+ the end into this list so that they're destroyed in tearDown.
+ """
+ self.to_destroy = []
+
+ def tearDown(self):
+ for obj in self.to_destroy:
+ obj.Destroy()
+
+ def test_arc_no_projection(self):
+ """Test BaseRenderer with arc layer and no projections"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (10, 10)]]]
+ store = SimpleShapeStore(SHAPETYPE_ARC, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ self.to_destroy.append(map)
+ layer = Layer("arc layer", store)
+ map.AddLayer(layer)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawLines', [P(10, 10), P(30, -10)]),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_polygon_no_projection(self):
+ """Test BaseRenderer with polygon layer and no projections"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(0, 0), (10, 10), (10, 0), (0, 0)]]]
+ store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ layer = Layer("polygon layer", store)
+ prop = layer.GetClassification().GetDefaultGroup().GetProperties()
+ prop.SetFill(Color(1, 1, 1))
+
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Color(1, 1, 1))),
+ ('SetPen', ('pen', Transparent)),
+ ('DrawPolygon', [P(10, 10), P(30, -10), P(30, 10),
+ P(10, 10)]),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawLines', [P(10, 10), P(30, -10), P(30, 10),
+ P(10, 10)]),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_complex_polygon(self):
+ """Test BaseRenderer with complex polygon and no projections"""
+ # A square inside a sqare. This has to be drawn with at least a
+ # draw polygon call and two draw lines calls.
+ shapes = [[[(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
+ [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]]]
+
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ layer = Layer("polygon layer", store)
+ prop = layer.GetClassification().GetDefaultGroup().GetProperties()
+ prop.SetFill(Color(1, 1, 1))
+
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Color(1, 1, 1))),
+ ('SetPen', ('pen', Transparent)),
+ ('DrawPolygon',
+ [P(10, 10), P(10, -10), P(30, -10), P(30, 10),
+ P(10, 10),
+ P(14, 6), P(26, 6), P(26, -6), P(14, -6),
+ P(14, 6),
+ P(10, 10)]),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawLines', [P(10, 10), P(10, -10), P(30, -10),
+ P(30, 10), P(10, 10)]),
+ ('DrawLines', [P(14, 6), P(26, 6), P(26, -6),
+ P(14, -6), P(14, 6)]),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_point_no_projection(self):
+ """Test BaseRenderer with point layer and no projections"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("UNKNOWN", 0.0, 1)])
+ shapes = [[[(0, 0)]], [[(10, 10)]]]
+ store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ layer = Layer("point layer", store)
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', 5, 5, 10, 10),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', 25, -15, 10, 10),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_projected_raster_layer(self):
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+ layer = RasterLayer("raster layer",
+ os.path.join("..", "Data", "iceland",
+ "island.tif"))
+
+ dc = MockDC(size = (20, 20))
+ renderer = SimpleRenderer(dc, map, 34, (800, 2250))
+
+ # The reference data as a base64 coded RAW image
+ raw_data = binascii.a2b_base64(
+ 'UmbmUmbmUmbmUmbmUmbmAtYCJooCAtICAq4CJooCArICAuICArICAuYCAs4COn4CO'
+ 'n4CAq4CAuICFpICUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmAuYCAqICAqoCAqoCFp'
+ 'ICJooCIo4CCpoCQnoGOn4CDpYCOn4CUmbmUmbmNo6aEpYCLoYCAqICGpICFpICUmb'
+ 'mAt4CUmbmNo6aAtICArYCAqoCKoYCMoICTnYKOn4CFpICUmbmUmbmUmbmUmbmAp4C'
+ 'NoICArYCAr4CCpoCAqYCCpoCEpYCHo4CFpICHo4CGpICFpICKoYCTnYKMoICAp4CU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmAtYCAroCArYCCpoCAtYCAroCAtICAsYCUmbmAt4CAq'
+ 'YCAroCMoICAs4CAs4CAtYCAt4CAqYCUmbmUmbmUmbmUmbmAtoCAtYCAq4CAtoCBp4'
+ 'CAroCAqoCAq4CAr4CDpYCGpICAt4CAsICDpYCArICCpoCHo4CAs4CAuICUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmAuICAqICFpYCAq4CDpoCAqYCFpICAqYCUmbmNo6aAsYCCpoCD'
+ 'pYCAqICAtoCUmbmAt4CAqoCCpoCAroCHo4CAsYCAq4CAsICAs4CAp4CUmbmAtYCAq'
+ 'YCIooCHo4CAsICAr4CAqICEpYCAs4CAqICArICDpYCEpYCEpYCAr4CUmbmEpYCAs4'
+ 'CAtICAs4CAqYCUmbmAtoCAp4CCpoCDpYCAq4CArICAqoCAqYCAqYCAtYCAtoCDpYC'
+ 'At4CUmbmUmbmUmbmUmbmAt4CAsoCAsoCAp4CAp4CCpoCAsoCAt4CNo6aUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmAt4CAtYCCpoCAqICAroCAr4CUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm\n')
+
+ raw_mask = binascii.a2b_base64(
+ '//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P//8P/'
+ '/8P//8P//8P//8P//8P\n')
+
+ raw_mask_inverted = binascii.a2b_base64(
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
+ 'AAAAAAAAAAAAAAAAAAA\n')
+
+ raw_alpha = binascii.a2b_base64(
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////////////////////'
+ '/////////////////////////////////////////////w==\n')
+
+ for opts, data in [[1, (raw_data, raw_mask, None)],
+ [1|4, (raw_data, raw_mask_inverted, None)],
+ [2, (raw_data, None, raw_alpha)]]:
+
+ img_data = renderer.projected_raster_layer(layer, "", "",
+ (-24, 65, -23, 66), [0, 0], (20, 20), opts)
+ self.assertEquals(img_data, data)
+
+ def test_projected_raster_decimalcommalocale(self):
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+ def _do_project_island():
+ """Project island.tif and return result."""
+ layer = RasterLayer("raster layer",
+ os.path.join("..", "Data", "iceland",
+ "island.tif"))
+
+ dc = MockDC(size = (10, 5))
+ renderer = SimpleRenderer(dc, map, 34, (800, 2250))
+
+ projection = "+proj=latlong +to_meter=0.017453 +ellps=clrk66"
+ new_projection = "+proj=utm +zone=27 +ellps=clrk66"
+
+ return renderer.projected_raster_layer(layer, \
+ projection, new_projection, \
+ (322003.1320390497, 6964094.1718668584, 876022.1891829354, 7460469.6276894147), [0, 0], (10,5), 1)
+
+ oldlocale = localessupport.setdecimalcommalocale()
+ img_data2 = _do_project_island()
+ locale.setlocale(locale.LC_NUMERIC, oldlocale)
+
+ img_data1 = _do_project_island()
+
+ self.assertEquals(img_data1, img_data2)
+
+ def test_raster_no_projection(self):
+ """Test BaseRenderer with raster layer and no projections
+
+ This test is very simple minded and perhaps can easily fail due
+ to round-off errors. It simply compares the complete BMP file
+ returned by gdalwarp.ProjectRasterFile to a BMP file data.
+ """
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+ map = Map("TestBaseRenderer")
+
+ layer = RasterLayer("raster layer",
+ os.path.join("..", "Data", "iceland",
+ "island.tif"))
+ layer.SetMaskType(layer.MASK_NONE)
+
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC(size = (20, 20))
+ renderer = SimpleRenderer(dc, map, 34, (800, 2250))
+
+ renderer.render_map()
+
+ # The following commented out code block can be used to generate
+ # the base64 coded reference image data
+ #hexed = binascii.b2a_base64(renderer.raster_data[2][0])
+ #while hexed:
+ #print repr(hexed[:65])
+ #hexed = hexed[65:]
+
+ # The reference data as a base64 coded RAW image
+ raw_data = binascii.a2b_base64(
+ 'UmbmUmbmUmbmUmbmUmbmAtYCJooCAtICAq4CJooCArICAuICArICAuYCAs4COn4CO'
+ 'n4CAq4CAuICFpICUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmAuYCAqICAqoCAqoCFp'
+ 'ICJooCIo4CCpoCQnoGOn4CDpYCOn4CUmbmUmbmNo6aEpYCLoYCAqICGpICFpICUmb'
+ 'mAt4CUmbmNo6aAtICArYCAqoCKoYCMoICTnYKOn4CFpICUmbmUmbmUmbmUmbmAp4C'
+ 'NoICArYCAr4CCpoCAqYCCpoCEpYCHo4CFpICHo4CGpICFpICKoYCTnYKMoICAp4CU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmAtYCAroCArYCCpoCAtYCAroCAtICAsYCUmbmAt4CAq'
+ 'YCAroCMoICAs4CAs4CAtYCAt4CAqYCUmbmUmbmUmbmUmbmAtoCAtYCAq4CAtoCBp4'
+ 'CAroCAqoCAq4CAr4CDpYCGpICAt4CAsICDpYCArICCpoCHo4CAs4CAuICUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmAuICAqICFpYCAq4CDpoCAqYCFpICAqYCUmbmNo6aAsYCCpoCD'
+ 'pYCAqICAtoCUmbmAt4CAqoCCpoCAroCHo4CAsYCAq4CAsICAs4CAp4CUmbmAtYCAq'
+ 'YCIooCHo4CAsICAr4CAqICEpYCAs4CAqICArICDpYCEpYCEpYCAr4CUmbmEpYCAs4'
+ 'CAtICAs4CAqYCUmbmAtoCAp4CCpoCDpYCAq4CArICAqoCAqYCAqYCAtYCAtoCDpYC'
+ 'At4CUmbmUmbmUmbmUmbmAt4CAsoCAsoCAp4CAp4CCpoCAsoCAt4CNo6aUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmAt4CAtYCCpoCAqICAroCAr4CUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmU'
+ 'mbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUm'
+ 'bmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmb'
+ 'mUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm'
+ 'UmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbmUmbm\n')
+
+ self.assertEquals(renderer.raster_data,
+ (20,20,(raw_data, None, None)))
+
+ self.assertEquals(renderer.raster_format, "RAW")
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_point_map_projection(self):
+ """Test BaseRenderer with point layer and map projection"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(10, 10)]]]
+ store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ map.SetProjection(MockProjection(-3, 3))
+ layer = Layer("point layer", store)
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', -55, -55, 10, 10),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_point_layer_projection(self):
+ """Test BaseRenderer with point layer and layer projection"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(9, 9)]]]
+ store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ layer = Layer("point layer", store)
+ layer.SetProjection(MockProjection(3, -3))
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', 11, 11, 10, 10),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+ def test_point_layer_and_map_projection(self):
+ """Test BaseRenderer with point layer and layer and map projection"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)])
+ shapes = [[[(9, 9)]]]
+ store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ map.SetProjection(MockProjection(-3, 3))
+ layer = Layer("point layer", store)
+ layer.SetProjection(MockProjection(3, -3))
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', -13, 23, 10, 10),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+
+ def test_point_with_classification(self):
+ """Test BaseRenderer with point layer and classification"""
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("UNKNOWN", 0.0, 1)])
+ shapes = [[[(0, 0)]], [[(10, 10)]]]
+ store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
+
+ map = Map("TestBaseRenderer")
+ layer = Layer("point layer", store)
+ group = ClassGroupSingleton(1)
+ group.GetProperties().SetFill(Color(0, 0, 1))
+ layer.GetClassification().AppendGroup(group)
+ layer.SetClassificationColumn("code")
+
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+
+ renderer.render_map()
+
+ self.assertEquals(dc.calls,
+ [('BeginDrawing',),
+ ('SetBrush', ('brush', Transparent)),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', 5, 5, 10, 10),
+ ('SetBrush', ('brush', Color(0, 0, 1))),
+ ('SetPen', ('pen', Color(0, 0, 0), 1)),
+ ('DrawEllipse', 25, -15, 10, 10),
+ ('SetFont', "label font"),
+ ('EndDrawing',)])
+
+
+ def test_renderer_extension(self):
+ """Test renderer with a renderer extension"""
+ class MyLayer(BaseLayer):
+ pass
+
+ calls = []
+ def my_renderer(renderer, layer):
+ calls.append((renderer, layer))
+ return ()
+
+ add_renderer_extension(MyLayer, my_renderer)
+
+ try:
+ map = Map("test_renderer_extension")
+ layer = MyLayer("my layer")
+ map.AddLayer(layer)
+ self.to_destroy.append(map)
+
+ dc = MockDC()
+ renderer = SimpleRenderer(dc, map, 2, (10, 10))
+ renderer.render_map()
+ finally:
+ init_renderer_extensions()
+
+ self.assertEquals(calls, [(renderer, layer)])
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_classgen.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_classgen.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_classgen.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,351 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Menu
+"""
+
+__version__ = "$Revision: 1528 $"
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.classgen import \
+ generate_singletons, \
+ generate_uniform_distribution, \
+ generate_quantiles, \
+ calculate_quantiles, \
+ grey_ramp, CustomRamp, FixedRamp
+from Thuban.Model.range import Range
+from Thuban.Model.color import Color
+
+from Thuban.Model.classification import ClassGroupRange, ClassGroupProperties
+
+class ClassGenTest(unittest.TestCase):
+
+ def doClassRangeTest(self, clazz, ranges):
+ self.assertEquals(clazz.GetNumGroups(), len(ranges))
+ for i in range(clazz.GetNumGroups()):
+ group = clazz.GetGroup(i)
+ r1 = str(Range(ranges[i]))
+ r2 = group.GetRange()
+ self.assertEquals(r1, r2)
+
+ self.doBoundsTest(clazz)
+
+ def doClassSingleTest(self, clazz, _list):
+ self.assertEquals(clazz.GetNumGroups(), len(_list))
+ for i in range(clazz.GetNumGroups()):
+ group = clazz.GetGroup(i)
+ self.assertEquals(group.GetValue(), _list[i])
+
+ self.doBoundsTest(clazz)
+
+ def doBoundsTest(self, clazz, ramp = grey_ramp):
+
+ #
+ # check that the properties are right (i.e. the first group
+ # is all white, the last is all black). This assumes that
+ # the grey_ramp, unless another is provided.
+ #
+ if clazz.GetNumGroups() >= 1:
+ groupF = clazz.GetGroup(0)
+ first = ramp.GetProperties(0)
+ self.assertEquals(groupF.GetProperties(), first)
+
+ if clazz.GetNumGroups() >= 2:
+ groupL = clazz.GetGroup(clazz.GetNumGroups() - 1)
+ last = ramp.GetProperties(1)
+ self.assertEquals(groupL.GetProperties(), last)
+
+ def test_generate_singletons(self):
+ """Test generate_singletons"""
+
+ eq = self.assertEquals
+ gs = generate_singletons
+ ramp = grey_ramp
+
+ _list = [1, 2, 3, 4]
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+ _list = range(0, 100)
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+ _list = range(-100, 100)
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+ _list = ['a', 'b', 'c', 'd']
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+ _list = []
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+ _list = [1]
+ cl = gs(_list, ramp)
+ self.doClassSingleTest(cl, _list)
+
+
+ def test_generate_uniform_distribution(self):
+ """Test generate_uniform_distribution"""
+
+ eq = self.assertEquals
+ gud = generate_uniform_distribution
+ ramp = grey_ramp
+
+ cl = gud(0, 99, 10, ramp, True)
+ self.doClassRangeTest(cl, ("[0;10[", "[10;20[", "[20;30[", "[30;40[",
+ "[40;50[", "[50;60[", "[60;70[", "[70;80[",
+ "[80;90[", "[90;99]"))
+
+ cl = gud(0, 99, 10, ramp, False)
+ self.doClassRangeTest(cl, ("[0;9.9[", "[9.9;19.8[", "[19.8;29.7[",
+ "[29.7;39.6[", "[39.6;49.5[", "[49.5;59.4[",
+ "[59.4;69.3[", "[69.3;79.2[", "[79.2;89.1[",
+ "[89.1;99.0]"))
+
+ cl = gud(1, 2, 2, ramp, False)
+ self.doClassRangeTest(cl, ("[1;1.5[", "[1.5;2]"))
+
+ cl = gud(1, 2, 2, ramp, True)
+ self.doClassRangeTest(cl, ("[1;2[", "[2;2]"))
+
+
+ def test_generate_quantiles(self):
+ """Test generate_quantiles"""
+
+ eq = self.assertEquals
+
+ #
+ # Test calculate_quantiles
+ #
+
+ gq = generate_quantiles
+
+ ramp = grey_ramp
+
+ adj, cl = gq([1, 2, 3, 4], [.25, .5, .75, 1.0], ramp, Range("[1;4]"))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[1;1]", "]1;2]", "]2;3]", "]3;4]"))
+
+ adj, cl = gq(range(0, 100), [.25, .5, .75, 1.0], ramp, Range("[0;100["))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[0;24]", "]24;49]", "]49;74]", "]74;100["))
+
+ adj, cl = gq(range(0, 100), [.33, .66, 1.0], ramp, Range("[0;100]"))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[0;32]", "]32;65]", "]65;100]"))
+
+ # negative input
+ adj,cl = gq(range(-100,100), [.33, .66, 1.0], ramp, Range("[-100;100]"))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[-100;-35]", "]-35;31]", "]31;100]"))
+
+ # unequal percentiles
+ adj,cl = gq(range(0, 100), [.25, .66, .8, 1.0], ramp, Range("[0;100]"))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[0;24]", "]24;65]", "]65;79]", "]79;100]"))
+
+ # input all the same
+ adj,cl = gq([1, 1, 1, 1], [.25, .5, .75, 1.0], ramp, Range("[1;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[1;4]",))
+
+ # empty input
+ adj,cl = gq([], [.25, .5, .75, 1.0], ramp, Range("[1;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ())
+
+ # empty range
+ adj,cl = gq([1, 2, 3, 4], [.25, .5, .75, 1.0], ramp, Range("]0;1["))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ())
+
+ # empty percentiles
+ self.assertRaises(ValueError, gq,
+ [1, 2, 3, 4], [], ramp, Range("]0;1["))
+
+ # single percentile
+ self.assertRaises(ValueError, gq,
+ [1, 2, 3, 4], [.5], ramp, Range("[0;4]"))
+
+ # more percentiles than input
+ adj,cl = gq([1], [.5, 1.0], ramp, Range("[0;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[0;4]",))
+
+ adj,cl = gq([1], [.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0], ramp, Range("[0;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[0;4]",))
+
+ # range smaller than the input
+ adj,cl = gq([1, 2, 3, 4], [.5, 1.0], ramp, Range("[2;3]"))
+ self.failIf(adj)
+ self.doClassRangeTest(cl, ("[2;2]","]2;3]"))
+
+ # range outside the input
+ adj,cl = gq([5, 6, 7, 8], [.5, 1.0], ramp, Range("[2;3]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ())
+
+ adj,cl = gq([1, 1, 1, 1, 1, 1], [.25, .5, .75, 1.0], ramp, Range("[1;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[1;4]",))
+
+ adj,cl = gq([1, 1, 1, 1, 1, 2, 3], [.25, .5, .75, 1.0], ramp, Range("[1;4]"))
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[1;1]", "]1;2]", "]2;4]"))
+
+ # adjusted quantiles
+ adj,cl = gq([1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5],
+ [.12, .24, .36, .50, .62, .76, .88, 1.0], ramp, Range("[1;5]"))
+
+ self.failUnless(adj)
+ self.doClassRangeTest(cl, ("[1;1]", "]1;2]", "]2;3]", "]3;4]", "]4;5]"))
+
+ def test_calculate_quantiles(self):
+ """Test calculate_quantiles"""
+
+ eq = self.assertEquals
+
+ #
+ # Test calculate_quantiles
+ #
+
+ cq = calculate_quantiles
+
+ result = cq([1, 2, 3, 4], [.25, .5, .75, 1.0], Range("[1;4]"))
+ eq(result, (0, 0, 3, [(0, .25), (1, .5), (2, .75), (3, 1.0)]))
+
+ result = cq(range(0, 100), [.25, .5, .75, 1.0], Range("[0;100]"))
+ eq(result, (0, 0, 99, [(24, .25), (49, .5), (74, .75), (99, 1.0)]))
+
+ result = cq(range(0, 100), [.33, .66, 1.0], Range("[0;100]"))
+ eq(result, (0, 0, 99, [(32, .33), (65, .66), (99, 1.0)]))
+
+ # negative input
+ result = cq(range(-100, 100), [.33, .66, 1.0], Range("[-100;100]"))
+ eq(result, (0, 0, 199, [(65, .33), (131, .66), (199, 1.0)]))
+
+ # unequal percentiles
+ result = cq(range(0, 100), [.25, .66, .8, 1.0], Range("[0;100]"))
+ eq(result, (0, 0, 99, [(24, .25), (65, .66), (79, .8), (99, 1.0)]))
+
+ # input all the same
+ result = cq([1, 1, 1, 1], [.25, .5, .75, 1.0], Range("[1;4]"))
+ eq(result, (1, 0, 3, [(3, 1.0)]))
+
+ # empty input
+ result = cq([], [.25, .5, .75, 1.0], Range("[1;4]"))
+ eq(result, None)
+
+ # empty range
+ result = cq([1, 2, 3, 4], [.25, .5, .75, 1.0], Range("]0;1["))
+ eq(result, None)
+
+ # empty percentiles
+ self.assertRaises(ValueError, cq, [1, 2, 3, 4], [], Range("]0;1["))
+
+ # single percentile
+ self.assertRaises(ValueError, cq, [1, 2, 3, 4], [.5], Range("[0;4]"))
+
+ # percentile doesn't cover range
+ self.assertRaises(ValueError, cq, [1, 2, 3, 4], [.5,.8], Range("[0;4]"))
+
+ # more percentiles than input
+ result = cq([1], [.5, 1.0], Range("[0;4]"))
+ eq(result, (1, 0, 0, [(0, 1.0)]))
+
+ result = cq([1], [.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0], Range("[0;4]"))
+ eq(result, (1, 0, 0, [(0, 1.0)]))
+
+ # range smaller than the input
+ result = cq([1, 2, 3, 4], [.5, 1.0], Range("[2;3]"))
+ eq(result, (0, 1, 2, [(1, .5), (2, 1.0)]))
+
+ # range outside the input
+ result = cq([5, 6, 7, 8], [.5, 1.0], Range("[2;3]"))
+ eq(result, None)
+
+ result = cq([1, 1, 1, 1, 1, 1], [.25, .5, .75, 1.0], Range("[1;4]"))
+ eq(result, (1, 0, 5, [(5, 1.0)]))
+
+ result = cq([1, 1, 1, 1, 1, 2, 3], [.25, .5, .75, 1.0], Range("[1;4]"))
+ eq(result, (1, 0, 6,
+ [(4, 0.7142857142857143), # the algorithm generated
+ (5, 0.8571428571428571), # these values, but they are
+ (6, 1.0)])) # right.
+
+ # adjusted quantiles
+ result = cq([1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5],
+ [.12, .24, .36, .50, .62, .76, .88, 1.0], Range("[1;5]"))
+ eq(result, (1, 0, 24, [(4, .2), (9, .4), (14, .6), (19, .8), (24, 1.0)]))
+
+
+class TestCustomRamp(unittest.TestCase):
+
+ def test_color_interpolation(self):
+ """Test CustomRamp color interpolation"""
+ start = ClassGroupProperties()
+ start.SetFill(Color(1, 1, 1))
+ start.SetLineColor(Color(0, 0, 0))
+
+ end = ClassGroupProperties()
+ end.SetFill(Color(1, 0, 0))
+ end.SetLineColor(Color(0, 1, 0))
+
+ ramp = CustomRamp(start, end)
+ half = ramp.GetProperties(0.5)
+ self.assertEquals(half.GetFill(), Color(1, 0.5, 0.5))
+ self.assertEquals(half.GetLineColor(), Color(0, 0.5, 0))
+
+
+class TestFixedRamp(unittest.TestCase):
+
+ def test(self):
+ """Test FixedRamp"""
+ eq = self.assertEquals
+
+ for lineColor, lineWidth, fillColor in \
+ [(None, None, None), (Color(1, 1, 1), None, None),
+ (None, 4, None), (None, None, Color(0, 1, 0)),
+ (Color(1, 1, 1), 4, None), (Color(1, 1, 1), None, Color(0, 1, 0)),
+ (None, 4, Color(0, 1, 0)), (Color(1, 1, 1), 4, Color(0, 1, 0))]:
+
+ framp = FixedRamp(grey_ramp, (lineColor, lineWidth, fillColor))
+
+ for i in [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]:
+ props = framp.GetProperties(i)
+ grey = Color(1 - i, 1 - i, 1 - i)
+ if lineColor is not None:
+ eq(props.GetLineColor(), lineColor)
+ else:
+ eq(props.GetLineColor(), grey)
+ if lineWidth is not None:
+ eq(props.GetLineWidth(), lineWidth)
+ if fillColor is not None:
+ eq(props.GetFill(), fillColor)
+ else:
+ eq(props.GetFill(), grey)
+
+if __name__ == "__main__":
+ unittest.main()
+
Added: packages/thuban/branches/upstream/current/test/test_classification.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_classification.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_classification.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,557 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Classification class
+"""
+
+__version__ = "$Revision: 2688 $"
+# $Source$
+# $Id: test_classification.py 2688 2006-06-30 12:27:20Z frank $
+
+import unittest
+
+import support
+support.initthuban()
+
+import copy
+
+from Thuban.Model.color import Color, Transparent, Black
+from Thuban.Model.classification import \
+ Classification, ClassGroup, \
+ ClassGroupDefault, ClassGroupSingleton, ClassGroupRange,\
+ ClassGroupPattern, ClassGroupProperties
+from Thuban.Model.messages import CLASS_CHANGED
+
+from Thuban.Model.range import Range
+
+
+
+# A few colors for use by the test cases
+red = Color(1, 0, 0)
+green = Color(0, 1, 0)
+blue = Color(0, 0, 1)
+
+
+class TestClassGroupProperties(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroupProperties"""
+
+ props = ClassGroupProperties()
+ self.assertEqual(props.GetLineColor(), Black)
+ self.assertEqual(props.GetLineWidth(), 1)
+ self.assertEqual(props.GetFill(), Transparent)
+
+ props.SetLineColor(red)
+ self.assertEqual(props.GetLineColor(), red)
+
+ props.SetLineColor(blue)
+ self.assertEqual(props.GetLineColor(), blue)
+
+ props.SetLineWidth(10)
+ self.assertEqual(props.GetLineWidth(), 10)
+
+ self.assertRaises(ValueError, props.SetLineWidth, -10)
+ self.assertEqual(props.GetLineWidth(), 10)
+
+ newProps1 = ClassGroupProperties()
+ newProps2 = ClassGroupProperties()
+ self.assertNotEqual(newProps1, props)
+ self.assertEqual(newProps1, newProps2)
+
+
+class TestClassGroup(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroup"""
+
+ # test constructor with no label
+ group = ClassGroup()
+ self.assertEqual(group.GetLabel(), "")
+
+ # test constructor with label
+ group = ClassGroup("hallo")
+ self.assertEqual(group.GetLabel(), "hallo")
+
+ # test SetLabel()/GetLabel()
+ group = ClassGroup("welt")
+ group.SetLabel("hallo")
+ self.assertEqual(group.GetLabel(), "hallo")
+
+ group.SetLabel("")
+ self.assertEqual(group.GetLabel(), "")
+
+ # test Matches
+ # Matches() is a virtual function...can't test it here
+ #
+ #self.assertEqual(group.Matches(None), False)
+ #self.assertEqual(group.Matches(1), False)
+ #self.assertEqual(group.Matches("hallo"), False)
+ #self.assertEqual(group.Matches([]), False)
+
+ # test GetProperties...also a virtual function
+ #self.assertEqual(group.GetProperties(), None)
+
+
+class TestClassGroupDefault(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroupDefault"""
+
+ defProps = ClassGroupProperties()
+
+ newProps = ClassGroupProperties()
+ newProps.SetLineColor(Color(.25, .5, .75))
+ newProps.SetLineWidth(5)
+ newProps.SetFill(Color(.12, .24, .36))
+
+ # test constructor
+
+ group = ClassGroupDefault(newProps)
+ self.assertEqual(group.GetProperties(), newProps)
+
+ group = ClassGroupDefault(newProps, "hallo")
+ self.assertEqual(group.GetProperties(), newProps)
+ self.assertEqual(group.GetLabel(), "hallo")
+
+ # test empty constructor
+ group = ClassGroupDefault()
+ props = group.GetProperties()
+
+ self.assertEqual(group.GetLabel(), "")
+ self.assertEqual(defProps, props)
+
+ # test Matches()
+ self.assertEqual(group.Matches(None), True)
+ self.assertEqual(group.Matches(1), True)
+ self.assertEqual(group.Matches("hallo"), True)
+ self.assertEqual(group.Matches([]), True)
+
+ # test SetProperties()/GetProperties()
+ group.SetProperties(newProps)
+ self.assertEqual(group.GetProperties(), newProps)
+
+ # test copy
+ groupCopy = copy.copy(group)
+ self.assertEqual(group, groupCopy)
+
+
+class TestClassGroupRange(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroupRange"""
+
+ defProps = ClassGroupProperties()
+ newProps = ClassGroupProperties()
+ newProps.SetLineColor(Color(.25, .5, .75))
+ newProps.SetLineWidth(5)
+ newProps.SetFill(Color(.12, .24, .36))
+
+ # test empty constructor
+ group = ClassGroupRange()
+
+ self.assertEqual(group.GetMin(), 0)
+ self.assertEqual(group.GetMax(), 1)
+ self.assertEqual(group.GetProperties(), defProps)
+ self.assertEqual(group.GetLabel(), "")
+
+ # test SetMax()
+ self.assertRaises(ValueError, group.SetMax, 0)
+ self.assertRaises(ValueError, group.SetMax, -1)
+ self.assertEquals(group.GetMax(), 1)
+ group.SetMax(2)
+ self.assertEquals(group.GetMax(), 2)
+
+ # test SetMin()
+ self.assertRaises(ValueError, group.SetMin, 2)
+ self.assertRaises(ValueError, group.SetMin, 3)
+ self.assertEquals(group.GetMin(), 0)
+ group.SetMin(-5)
+ self.assertEquals(group.GetMin(), -5)
+
+ # test SetProperties()/GetProperties()
+ group.SetProperties(newProps)
+ self.assertEqual(group.GetProperties(), newProps)
+
+ # test SetRange()
+ self.assertRaises(ValueError, group.SetRange, (1, 0))
+ group.SetRange(Range("]-oo;6]"))
+ self.assertEqual(group.GetRange(), "]-oo;6]")
+ group.SetRange((-5, 5))
+ self.assertEqual(group.GetRange(), "[-5;5[")
+
+ # test Matches()
+ self.assertEqual(group.Matches(-6), False)
+ self.assertEqual(group.Matches(-5), True)
+ self.assertEqual(group.Matches(0), True)
+ self.assertEqual(group.Matches(4), True)
+ self.assertEqual(group.Matches(5), False)
+
+ # test copy
+ groupCopy = copy.copy(group)
+ self.assertEqual(group, groupCopy)
+
+
+class TestClassGroupSingleton(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroupSingleton"""
+
+ defProps = ClassGroupProperties()
+ newProps = ClassGroupProperties()
+ newProps.SetLineColor(Color(.25, .5, .75))
+ newProps.SetLineWidth(5)
+ newProps.SetFill(Color(.12, .24, .36))
+
+ # test empty constructor
+ group = ClassGroupSingleton()
+
+ self.assertEqual(group.GetValue(), 0)
+ self.assertEqual(group.GetProperties(), defProps)
+ self.assertEqual(group.GetLabel(), "")
+
+ # test SetProperties()/GetProperties()
+ group.SetProperties(newProps)
+ self.assertEqual(group.GetProperties(), newProps)
+
+ # test SetValue()
+ group.SetValue(5)
+ self.assertEqual(group.GetValue(), 5)
+
+ # test Matches()
+ self.assertEqual(group.Matches(0), False)
+ self.assertEqual(group.Matches(5), True)
+
+ group.SetValue("5")
+ self.assertNotEqual(group.GetValue(), 5)
+
+ # test Matches()
+ self.assertEqual(group.Matches(5), False)
+ self.assertEqual(group.Matches("5"), True)
+
+ group.SetValue("hallo")
+ self.assertEqual(group.GetValue(), "hallo")
+
+ # test Matches()
+ self.assertEqual(group.Matches("HALLO"), False)
+ self.assertEqual(group.Matches("hallo"), True)
+
+ # test copy
+ groupCopy = copy.copy(group)
+ self.assertEqual(group, groupCopy)
+
+
+class TestClassGroupPattern(unittest.TestCase):
+
+ def test(self):
+ """Test ClassGroupPattern"""
+
+ defProps = ClassGroupProperties()
+ newProps = ClassGroupProperties()
+ newProps.SetLineColor(Color(.25, .5, .75))
+ newProps.SetLineWidth(5)
+ newProps.SetFill(Color(.12, .24, .36))
+
+ # test empty constructor
+ group = ClassGroupPattern()
+
+ self.assertEqual(group.GetPattern(), "")
+ self.assertEqual(group.GetProperties(), defProps)
+ self.assertEqual(group.GetLabel(), "")
+
+ # test SetProperties()/GetProperties()
+ group.SetProperties(newProps)
+ self.assertEqual(group.GetProperties(), newProps)
+
+ # test SetPattern()
+ group.SetPattern("A")
+ self.assertEqual(group.GetPattern(), "A")
+
+ # test Matches()
+ self.assertEqual(group.Matches("CBA"), False)
+ self.assertEqual(group.Matches("ABC"), True)
+
+ group.SetPattern("a")
+ self.assertNotEqual(group.GetPattern(), "A")
+
+ # test Matches()
+ self.assertEqual(group.Matches("Abc"), False)
+ self.assertEqual(group.Matches("aBC"), True)
+
+ group.SetPattern("hallo")
+ self.assertEqual(group.GetPattern(), "hallo")
+
+ # test Matches()
+ self.assertEqual(group.Matches("HALLO"), False)
+ self.assertEqual(group.Matches("hallo"), True)
+
+ # test copy
+ groupCopy = copy.copy(group)
+ self.assertEqual(group, groupCopy)
+
+
+class TestClassification(unittest.TestCase, support.SubscriberMixin):
+
+ """Test cases for Classification"""
+
+ def setUp(self):
+ self.clazz = Classification()
+ self.clazz.Subscribe(CLASS_CHANGED, self.subscribe_with_params,
+ CLASS_CHANGED)
+ self.clear_messages()
+
+ def tearDown(self):
+ self.clear_messages()
+ self.clazz.Destroy()
+ del self.clazz
+
+ def test_defaults(self):
+ """Test Classification default settings"""
+ self.assertEqual(self.clazz.FindGroup(-1),
+ self.clazz.GetDefaultGroup())
+ self.assertEqual(self.clazz.GetDefaultLineColor(), Black)
+ self.assertEqual(self.clazz.GetDefaultFill(), Transparent)
+ self.assertEqual(self.clazz.GetDefaultLineWidth(), 1)
+
+ # The default group is not counted, hence 0 groups
+ self.assertEqual(self.clazz.GetNumGroups(), 0)
+
+ # No messages should have been sent so far
+ self.check_messages([])
+
+ def test_set_default_properties(self):
+ """Test Classification.SetDefaultLineColor and SetDefaultFill"""
+ # No messages so far
+ self.check_messages([])
+
+ # Change the default line color
+ self.clazz.SetDefaultLineColor(red)
+ self.assertEqual(self.clazz.GetDefaultLineColor(), red)
+ self.assertEqual(self.clazz.GetDefaultFill(), Transparent)
+ self.assertEqual(self.clazz.GetDefaultLineWidth(), 1)
+
+ self.check_messages([(CLASS_CHANGED,)])
+ self.clear_messages()
+
+ self.clazz.SetDefaultFill(green)
+ self.assertEqual(self.clazz.GetDefaultFill(), green)
+ self.assertEqual(self.clazz.GetDefaultLineColor(), red)
+ self.assertEqual(self.clazz.GetDefaultLineWidth(), 1)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ self.check_messages([(CLASS_CHANGED,)])
+ self.clear_messages()
+
+ self.clazz.SetDefaultLineWidth(10)
+ self.assertEqual(self.clazz.GetDefaultFill(), green)
+ self.assertEqual(self.clazz.GetDefaultLineColor(), red)
+ self.assertEqual(self.clazz.GetDefaultLineWidth(), 10)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ def test_set_default_group(self):
+ """Test Classification.SetDefaultGroup()"""
+ prop = ClassGroupProperties()
+ prop.SetLineColor(blue)
+ prop.SetLineWidth(5)
+ prop.SetFill(red)
+
+ self.clazz.SetDefaultGroup(ClassGroupDefault(prop))
+ self.assertEqual(self.clazz.GetDefaultFill(), red)
+ self.assertEqual(self.clazz.GetDefaultLineColor(), blue)
+ self.assertEqual(self.clazz.GetDefaultLineWidth(), 5)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ def test_add_singleton(self):
+ """Test Classification.AppendGroup(ClassGroupSingleton())"""
+ self.assertEquals(self.clazz.FindGroup(5),
+ self.clazz.GetDefaultGroup())
+
+ s = ClassGroupSingleton(5)
+ self.clazz.AppendGroup(s)
+ self.check_messages([(CLASS_CHANGED,)])
+ self.assertEquals(self.clazz.FindGroup(5), s)
+ self.assertEquals(self.clazz.FindGroup(0),
+ self.clazz.GetDefaultGroup())
+
+ def test_add_range(self):
+ """Test Classification.AppendGroup(ClassGroupRange())"""
+ self.assertEquals(self.clazz.FindGroup(0),
+ self.clazz.GetDefaultGroup())
+
+ r = ClassGroupRange((-10, 10))
+ self.clazz.AppendGroup(r)
+ self.check_messages([(CLASS_CHANGED,)])
+ self.assertEquals(self.clazz.FindGroup(-11),
+ self.clazz.GetDefaultGroup())
+ self.assertEquals(self.clazz.FindGroup(-10), r)
+ self.assertEquals(self.clazz.FindGroup(9), r)
+ self.assertEquals(self.clazz.FindGroup(5), r)
+ self.assertEquals(self.clazz.FindGroup(10),
+ self.clazz.GetDefaultGroup())
+
+ def test_add_pattern(self):
+ """Test Classification.AppendGroup(ClassGroupPattern())"""
+ self.assertEquals(self.clazz.FindGroup(5),
+ self.clazz.GetDefaultGroup())
+
+ s = ClassGroupPattern("A")
+ self.clazz.AppendGroup(s)
+ self.check_messages([(CLASS_CHANGED,)])
+ self.assertEquals(self.clazz.FindGroup("A"), s)
+ self.assertEquals(self.clazz.FindGroup("B"),
+ self.clazz.GetDefaultGroup())
+
+ def test_multiple_groups_numerical(self):
+ """Test numerical Classification with multiple groups"""
+ # two singletons matching 1 to test whether they're tested in
+ # the right order. Use a non default fill on the second to make
+ # it compare unequal to the first.
+ s1 = ClassGroupSingleton(1)
+ s1a = ClassGroupSingleton(1)
+ s1a.GetProperties().SetFill(blue)
+ # Sanity check: are they considered different?
+ self.assertNotEqual(s1, s1a)
+
+ s2 = ClassGroupSingleton(2)
+ r = ClassGroupRange((-10, 10))
+
+ self.clazz.AppendGroup(s1)
+ self.clazz.AppendGroup(s2)
+ self.clazz.AppendGroup(s1a)
+ self.clazz.AppendGroup(r)
+ self.check_messages([(CLASS_CHANGED,), (CLASS_CHANGED,),
+ (CLASS_CHANGED,), (CLASS_CHANGED,)])
+
+ self.assertEquals(self.clazz.FindGroup(-11),
+ self.clazz.GetDefaultGroup())
+ self.assertEquals(self.clazz.FindGroup(-10), r)
+ self.assertEquals(self.clazz.FindGroup(1), s1)
+ self.assertEquals(self.clazz.FindGroup(2), s2)
+ self.assertEquals(self.clazz.FindGroup(3), r)
+ self.assertEquals(self.clazz.FindGroup(9), r)
+ self.assertEquals(self.clazz.FindGroup(10),
+ self.clazz.GetDefaultGroup())
+
+ def test_multiple_groups_textual(self):
+ """Test textual Classification with multiple groups"""
+ # A singleton and a pattern matching 'A' to test whether
+ # they're tested in the right order. Use a non default fill
+ # on the pattern to make it compare unequal to the first.
+ s = ClassGroupSingleton("A")
+ p = ClassGroupPattern("A")
+ p.GetProperties().SetFill(blue)
+ # Sanity check: are they considered different?
+ self.assertNotEqual(s, p)
+
+ self.clazz.AppendGroup(s)
+ self.clazz.AppendGroup(p)
+ self.check_messages([(CLASS_CHANGED,), (CLASS_CHANGED,)])
+
+ self.assertEquals(self.clazz.FindGroup("bca"),
+ self.clazz.GetDefaultGroup())
+ self.assertEquals(self.clazz.FindGroup("A"), s)
+ self.assertEquals(self.clazz.FindGroup("Abc"), p)
+ self.assertEquals(self.clazz.FindGroup("abc"),
+ self.clazz.GetDefaultGroup())
+
+ def test_insert_group(self):
+ """Test Classification.InsertGroup()"""
+ s1 = ClassGroupSingleton(1)
+ s2 = ClassGroupSingleton(2)
+ r = ClassGroupRange((0, 10))
+
+ self.clazz.AppendGroup(s1)
+ self.clazz.AppendGroup(r)
+ self.assertEquals(self.clazz.FindGroup(2), r)
+ self.clear_messages()
+
+ self.clazz.InsertGroup(1, s2)
+ self.assertEquals(self.clazz.FindGroup(2), s2)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ def test_remove_group(self):
+ """Test Classification.RemoveGroup()"""
+ s1 = ClassGroupSingleton(1)
+ s2 = ClassGroupSingleton(2)
+ r = ClassGroupRange((0, 10))
+
+ self.clazz.AppendGroup(s1)
+ self.clazz.AppendGroup(s2)
+ self.clazz.AppendGroup(r)
+ self.assertEquals(self.clazz.FindGroup(2), s2)
+ self.clear_messages()
+
+ self.clazz.RemoveGroup(1)
+ self.assertEquals(self.clazz.FindGroup(2), r)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ def test_replace_group(self):
+ """Test Classification.ReplaceGroup()"""
+ s1 = ClassGroupSingleton(1)
+ s2 = ClassGroupSingleton(2)
+ r = ClassGroupRange((0, 10))
+
+ self.clazz.AppendGroup(s2)
+ self.clazz.AppendGroup(r)
+ self.assertEquals(self.clazz.FindGroup(2), s2)
+ self.assertEquals(self.clazz.FindGroup(1), r)
+ self.clear_messages()
+
+ self.clazz.ReplaceGroup(0, s1)
+ self.assertEquals(self.clazz.FindGroup(2), r)
+ self.assertEquals(self.clazz.FindGroup(1), s1)
+ self.check_messages([(CLASS_CHANGED,)])
+
+ def test_deepcopy_numerical(self):
+ """Test deepcopy(numerical Classification())"""
+ self.clazz.AppendGroup(ClassGroupSingleton(5))
+ self.clazz.AppendGroup(ClassGroupRange((-10, 10)))
+
+ clazz = copy.deepcopy(self.clazz)
+
+ self.assertEquals(clazz.GetNumGroups(), self.clazz.GetNumGroups())
+
+ for i in range(clazz.GetNumGroups()):
+ self.assertEquals(clazz.GetGroup(i), self.clazz.GetGroup(i))
+
+ def test_deepcopy_textual(self):
+ """Test deepcopy(textual Classification())"""
+ self.clazz.AppendGroup(ClassGroupSingleton("A"))
+ self.clazz.AppendGroup(ClassGroupPattern("B"))
+
+ clazz = copy.deepcopy(self.clazz)
+
+ self.assertEquals(clazz.GetNumGroups(), self.clazz.GetNumGroups())
+
+ for i in range(clazz.GetNumGroups()):
+ self.assertEquals(clazz.GetGroup(i), self.clazz.GetGroup(i))
+
+
+ def test_iterator(self):
+ """Test Classification iteration"""
+ groups = [ClassGroupSingleton(5), ClassGroupSingleton(5),
+ ClassGroupRange((-3, 3)), ClassGroupSingleton(-5),
+ ClassGroupDefault()]
+
+ for g in groups:
+ self.clazz.AppendGroup(g)
+
+ def convert(group):
+ if isinstance(group, ClassGroupDefault): return 0
+ if isinstance(group, ClassGroupSingleton): return 1
+ if isinstance(group, ClassGroupRange): return 2
+
+ list = []
+ for g in self.clazz:
+ list.append(convert(g))
+
+ self.assertEquals(list, [0, 1, 1, 2, 1, 0])
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_classmapper.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_classmapper.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_classmapper.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,92 @@
+# Copyright (c) 2004 by Intevation GmbH
+# Authors:
+# Martin Schulze <joey at infodrom.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Test case for the Thuban ClassMapper.
+
+"""
+
+__version__ = "$Revision: 2298 $"
+# $Source$
+# $Id: test_classmapper.py 2298 2004-07-26 15:59:46Z joey $
+
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Lib.classmapper import ClassMapper
+
+class TestMapping(unittest.TestCase):
+
+ def test_mapper(self):
+ """
+ Test ClassMapper
+ """
+
+ class MyClass:
+ pass
+
+ class MySecondClass:
+ def hello(self):
+ return "Hello World!"
+
+ class MyThirdClass:
+ def hello(self):
+ return "Hello Earth!"
+
+ mapping = ClassMapper()
+ instance = MyClass()
+
+ # See if an empty mapping really returns False
+ #
+ self.assertEqual(mapping.get(instance), None)
+ self.assertEqual(mapping.has(instance), False)
+
+ # See if an installed mapping works
+ #
+ mapping.add(MyClass, MySecondClass)
+ self.assertEqual(mapping.get(instance), MySecondClass)
+ self.assertEqual(mapping.has(instance), True)
+
+ # Ensure that it's really the class we put in and the method
+ # is available as expected.
+ #
+ myinst = mapping.get(instance)()
+ self.assertEqual(myinst.hello(), "Hello World!")
+
+ second = ClassMapper()
+
+ # Test if a second mapper gets mixed ubp with the first one.
+ #
+ self.assertEqual(second.get(instance), None)
+
+ second.add(MyClass, MyThirdClass)
+ self.assertEqual(second.get(instance), MyThirdClass)
+ self.assertEqual(second.has(instance), True)
+
+ # Ensure that it's really the class we put in and the method
+ # is available as expected.
+ #
+ myinst = second.get(instance)()
+ self.assertEqual(myinst.hello(), "Hello Earth!")
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_color.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_color.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_color.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,86 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Thuban.Model.color module
+"""
+
+__version__ = "$Revision: 1547 $"
+# $Source$
+# $Id: test_color.py 1547 2003-08-05 12:38:58Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.color import Color, Transparent
+
+
+class TestColor(unittest.TestCase):
+
+ def test(self):
+ """Test Color"""
+ # The color objects are very simple. We just have to test
+ # whether instantiating one assigns the colors to the right
+ # instance variables and whether the correct hex string is
+ # produced
+ color = Color(0, 0.5, 1.0)
+ self.assertEquals(color.red, 0.0)
+ self.assertEquals(color.green, 0.5)
+ self.assertEquals(color.blue, 1.0)
+ self.assertEquals(color.hex().lower(), "#007fff")
+
+ def test_repr(self):
+ """Test Color repr"""
+ self.assertEquals(repr(Color(0, 0.5, 0.75)), "Color(0, 0.5, 0.75)")
+
+ def test_equality(self):
+ """Test Color equality testing"""
+ self.failUnless(Color(0, 0, 0) == Color(0.0, 0.0, 0.0))
+ self.failUnless(Color(0, 0.5, 1.0) == Color(0.0, 0.5, 1.0))
+ self.failIf(Color(0, 0.5, 1.0) == Color(0.0, 0.5, 0.75))
+ self.failIf(Color(0, 0.5, 1.0) == (0.0, 0.5, 1.0))
+ self.failIf((0, 0.5, 1.0) == Color(0.0, 0.5, 1.0))
+
+ def test_inequality(self):
+ """Test Color inequality testing"""
+ self.failIf(Color(0, 0, 0) != Color(0.0, 0.0, 0.0))
+ self.failIf(Color(0, 0.5, 1.0) != Color(0.0, 0.5, 1.0))
+ self.failUnless(Color(0, 0.5, 1.0) != Color(0.0, 0.5, 0.75))
+ self.failUnless(Color(0, 0.5, 1.0) != (0.0, 0.5, 1.0))
+ self.failUnless((0, 0.5, 1.0) != Color(0.0, 0.5, 1.0))
+
+class TestTransparent(unittest.TestCase):
+
+ def test_repr(self):
+ """Test Transparent repr"""
+ self.assertEquals(repr(Transparent), "Transparent")
+
+ def test_hex(self):
+ """Test Transparent.hex()"""
+ self.assertEquals(Transparent.hex(), "None")
+
+ def test_equality(self):
+ """Test Transparent equality testing"""
+ self.failUnless(Transparent == Transparent)
+ self.failIf(Transparent == Color(0.0, 0.5, 1.0))
+ self.failIf(Color(0.0, 0.5, 1.0) == Transparent)
+ self.failIf(None == Transparent)
+ self.failIf(Transparent == None)
+
+ def test_inequality(self):
+ """Test Transparent inequality testing"""
+ self.failIf(Transparent != Transparent)
+ self.failUnless(Transparent != Color(0.0, 0.5, 1.0))
+ self.failUnless(Color(0.0, 0.5, 1.0) != Transparent)
+ self.failUnless(None != Transparent)
+ self.failUnless(Transparent != None)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_command.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_command.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_command.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,132 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Command class
+"""
+
+__version__ = "$Revision: 537 $"
+# $Source$
+# $Id: test_command.py 537 2003-03-14 20:43:50Z bh $
+
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.UI.command import Command, ToolCommand
+
+class MockContext:
+
+ pass
+
+
+class BaseCommandTest(unittest.TestCase):
+
+ def setUp(self):
+ self.command_args = None
+
+ def command(self, *args):
+ """Method to use as the command function.
+
+ Bind all args except self to self.command_args as a tuple.
+ """
+ self.command_args = args
+
+ def context(self):
+ """Return a context object"""
+ return MockContext()
+
+class TestCommand(BaseCommandTest):
+
+ def test_static_command(self):
+ """Test Command object with no callbacks"""
+ cmd = Command("do_something", "Do Something", self.command)
+ self.assertEquals(cmd.Name(), "do_something")
+ self.assertEquals(cmd.Title(), "Do Something")
+ self.assertEquals(cmd.HelpText(), "")
+ self.assertEquals(cmd.Icon(), "")
+ self.failIf(cmd.IsDynamic())
+ self.failIf(cmd.IsTool())
+
+ context = self.context()
+ self.assert_(cmd.Sensitive(context))
+ self.failIf(cmd.Checked(context))
+
+ # Execute the command with just the context
+ cmd.Execute(context)
+ self.assertEquals(self.command_args, (context,))
+
+ # Execute the command with additional parameters
+ cmd.Execute(context, "abc")
+ self.assertEquals(self.command_args, (context, "abc"))
+
+class TestDynamicCommand(BaseCommandTest):
+
+ def setUp(self):
+ BaseCommandTest.setUp(self)
+ self.is_sensitive = 0
+ self.is_checked = 0
+ self.dynamic_text = ""
+
+ def sensitive(self, context):
+ return self.is_sensitive
+
+ def checked(self, context):
+ return self.is_checked
+
+ def dyntext(self, context):
+ return self.dynamic_text
+
+ def context(self):
+ """Return a context object"""
+ return MockContext()
+
+ def test_dynamic_sensitivity(self):
+ """Test Command object with dynamic sensitivity"""
+ cmd = Command("do_something", "Do Something", self.command,
+ sensitive = self.sensitive)
+ self.assert_(cmd.IsDynamic())
+
+ context = self.context()
+ self.failIf(cmd.Sensitive(context))
+ self.is_sensitive = 1
+ self.assert_(cmd.Sensitive(context))
+
+ def test_dynamic_checked(self):
+ """Test Command object with dynamic checked flag"""
+ cmd = Command("do_something", "Do Something", self.command,
+ checked = self.checked)
+ self.assert_(cmd.IsDynamic())
+
+ context = self.context()
+ self.failIf(cmd.Checked(context))
+ self.is_checked = 1
+ self.assert_(cmd.Checked(context))
+
+ def test_dynamic_title(self):
+ """Test Command object with dynamic title"""
+ cmd = Command("do_something", "Do Something", self.command,
+ dyntext = self.dyntext)
+ self.assert_(cmd.IsDynamic())
+ self.assert_(cmd.HasDynText())
+
+ context = self.context()
+ self.assertEquals(cmd.DynText(context), "")
+ self.dynamic_text = "A Dynamic Title"
+ self.assertEquals(cmd.DynText(context), "A Dynamic Title")
+
+ def test_tool_command(self):
+ """Test ToolCommand object"""
+ cmd = ToolCommand("do_something", "Do Something", self.command,
+ checked = self.checked)
+ self.assert_(cmd.IsDynamic())
+ self.assert_(cmd.IsTool())
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_connector.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_connector.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_connector.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,426 @@
+# Copyright (c) 2002, 2003, 2004 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Connector class
+"""
+
+__version__ = "$Revision: 2586 $"
+# $Source$
+# $Id: test_connector.py 2586 2005-03-16 14:55:21Z bh $
+
+import sys
+import unittest
+import traceback
+
+import support
+support.initthuban()
+
+from Thuban.Lib.connector import Connector, Publisher, Conduit, ConnectorError
+
+# some messages used in the tests
+SIMPLE = "SIMPLE"
+PARAM = "PARAM"
+
+class SimplePublisher:
+
+ """A version of Publisher that uses a specific connector.
+
+ The Publisher class in Thuban.Lib.connector uses the global
+ connector in the same module.
+ """
+
+ def __init__(self, connector):
+ self.connector = connector
+
+ def __del__(self):
+ self.connector.RemovePublisher(self)
+
+ def issue(self):
+ """Issue a SIMPLE message without parameters"""
+ self.connector.Issue(self, SIMPLE)
+
+ def issue_arg(self):
+ """Issue a PARAM message with 42 as parameter"""
+ self.connector.Issue(self, PARAM, 42)
+
+
+class RealPublisher(Publisher):
+
+ """Extended version of Publisher for testing purposes.
+
+ Publisher is not intended to be used directly. It is used as a base
+ class for objects that send messages when they change. So we do just
+ that here and derive from Publisher to provide some simple methods
+ that issue messages.
+ """
+
+ def simple_action(self):
+ """Issue a SIMPLE message without parameters"""
+ self.issue(SIMPLE)
+
+ def param_action(self):
+ """Issue a PARAM message with 42 as parameter"""
+ self.issue(PARAM, 42)
+
+
+class Receiver:
+
+ """Class to be used as a generic receiver of messages.
+
+ An instance of this class has some methods that can be used as
+ subscribers for messages. These messages put information about the
+ messages they received into the public instance variable messages.
+ See the method's doc-strings for more information.
+
+ Furthermore, the class is instantiated with a test case object as
+ parameter and the instance notifies the test case when it's being
+ instantiated and deleted so that the test case can determine which
+ objects weren't deleted.
+ """
+
+ def __init__(self, testcase):
+ """Initialize the object for the given testcase.
+
+ Call the testcase's expect_delete method with self as parameter.
+ """
+ self.testcase = testcase
+ self.testcase.expect_delete(self)
+ self.reset()
+
+ def __del__(self):
+ """Tell the test case that the object has been deleted"""
+ self.testcase.deleted(self)
+
+ def reset(self):
+ """Clear the list of received messages"""
+ self.messages = []
+
+ def no_params(self):
+ """Method for subscriptions without parameters
+
+ Add the tuple ("no_params",) to self.messages
+ """
+ self.messages.append(("no_params",))
+
+ def with_params(self, *args):
+ """Method for subscriptions with parameters
+
+ Add a tuple with the string 'params' followed by the arguments
+ of this function (except for the self parameter) to
+ self.messages.
+ """
+ self.messages.append(("params",) + args)
+
+
+
+class DeletionTestMixin:
+
+ """Mixin class to check for memory leaks.
+
+ Mixin class for test that want to determine whether certain objects
+ have been destroyed.
+
+ This class maintains two lists, deleted_objects and
+ expected_deletions to determine whether all objects which are
+ expected to be deleted by a test are actually deleted.
+ """
+
+ def setUp(self):
+ """Initialize self.deleted_objects and self.expected_deletions"""
+ self.deleted_objects = []
+ self.expected_deletions = []
+
+ def expect_delete(self, obj):
+ """Append the id of obj to the self.expected_deletions"""
+ self.expected_deletions.append(id(obj))
+
+ def deleted(self, obj):
+ """Append the id of obj to the self.deleted_objects"""
+ self.deleted_objects.append(id(obj))
+
+ def check_deletions(self):
+ """Assert equality of self.expected_deletions and self.deleted_objects
+
+ This check simply compares the lists for equality and thus
+ effectively assumes that the objects are deleted in the same
+ order in which they're added to the list which if used only for
+ Receiver instances is the order in which they're instantiated.
+ """
+ self.assertEquals(self.expected_deletions, self.deleted_objects)
+
+
+class ConnectorTest(unittest.TestCase, DeletionTestMixin):
+
+ """Test cases for the Connector class.
+
+ These tests use the SimplePublisher class instead of the Publisher
+ class in Thuban.Lib.connector because we only want to test the
+ connector here.
+ """
+
+ def setUp(self):
+ """Extend the inherited method to create a Connector instance.
+
+ Bind the Connector to self.connector.
+ """
+ self.connector = Connector()
+ DeletionTestMixin.setUp(self)
+
+ def test_issue_simple(self):
+ """Test connector issue without parameters"""
+ # Make a publisher and a subscriber and connect the two
+ pub = SimplePublisher(self.connector)
+ rec = Receiver(self)
+ self.connector.Connect(pub, SIMPLE, rec.no_params, ())
+
+ # now the publisher should have subscribers
+ self.assert_(self.connector.HasSubscribers(pub))
+
+ # Issue a message and check whether the receiver got it
+ pub.issue()
+ self.assertEquals(rec.messages, [("no_params",)])
+ rec.reset()
+
+ # disconnect and check that the message doesn't get send anymore
+ self.connector.Disconnect(pub, SIMPLE, rec.no_params, ())
+ pub.issue()
+ self.assertEquals(rec.messages, [])
+
+ # now the publisher should have no subscribers
+ self.failIf(self.connector.HasSubscribers(pub))
+
+ # make sure that all references have been deleted
+ del rec
+ self.check_deletions()
+
+ def test_issue_param(self):
+ """Test connector issue with parameters"""
+ pub = SimplePublisher(self.connector)
+ rec = Receiver(self)
+ # Three cases: 1. The parameter supplied by pub.issue_arg, 2.
+ # only the parameter given when connecting, 3. both
+ self.connector.Connect(pub, PARAM, rec.with_params, ())
+ self.connector.Connect(pub, SIMPLE, rec.with_params, ("deliverator",))
+ self.connector.Connect(pub, PARAM, rec.with_params, ("loglo",))
+
+ pub.issue_arg()
+ pub.issue()
+ self.assertEquals(rec.messages, [("params", 42),
+ ("params", 42, "loglo"),
+ ("params", "deliverator")])
+
+ # make sure that all references have been deleted
+ self.connector.RemovePublisher(pub)
+ del rec
+ self.check_deletions()
+
+ def test_cyclic_references(self):
+ """Test whether connector avoids cyclic references"""
+ pub = SimplePublisher(self.connector)
+ rec = Receiver(self)
+ self.connector.Connect(pub, SIMPLE, rec.no_params, ())
+
+ # deleting pub and rec should be enough that the last reference
+ # to rec has been dropped because the connector doesn't keep
+ # references to the publishers and SimplePublisher's __del__
+ # method removes all subscriptions
+ del pub
+ del rec
+ self.check_deletions()
+
+ def test_disconnect_in_receiver(self):
+ """Test unsubscribing from a channel while receiving a message
+
+ There was a bug in the connector implementation in the following
+ situation:
+
+ - 2 receivers for the same channel
+
+ - the reiver called first unsubscribes itself from that channel
+ in response to a message on that channel
+
+ Now the second receiver is never called because the list of
+ receivers was modified by Disconnect while the connecter was
+ iterating over it.
+ """
+ messages = []
+ def rec1(*args):
+ try:
+ messages.append("rec1")
+ self.connector.Disconnect(None, SIMPLE, rec1, ())
+ except:
+ self.fail("Exception in rec1")
+ def rec2(*args):
+ try:
+ messages.append("rec2")
+ self.connector.Disconnect(None, SIMPLE, rec2, ())
+ except:
+ self.fail("Exception in rec1")
+
+ self.connector.Connect(None, SIMPLE, rec1, ())
+ self.connector.Connect(None, SIMPLE, rec2, ())
+
+ self.connector.Issue(None, SIMPLE)
+
+ self.assertEquals(messages, [("rec1"), ("rec2")])
+
+
+class TestPublisher(unittest.TestCase, DeletionTestMixin):
+
+ """Tests for the Publisher class"""
+
+ def setUp(self):
+ DeletionTestMixin.setUp(self)
+
+ def test_issue_simple(self):
+ """Test Publisher message without parameters"""
+ # Make a publisher and a subscriber and connect the two
+ pub = RealPublisher()
+ rec = Receiver(self)
+ pub.Subscribe(SIMPLE, rec.no_params)
+
+ # Issue a message and check whether the receiver got it
+ pub.simple_action()
+ self.assertEquals(rec.messages, [("no_params",)])
+ rec.reset()
+
+ # disconnect and check that the message doesn't get sent anymore
+ pub.Unsubscribe(SIMPLE, rec.no_params)
+ pub.simple_action()
+ self.assertEquals(rec.messages, [])
+
+ # make sure that all references have been deleted
+ del rec
+ self.check_deletions()
+
+ def test_issue_param(self):
+ """Test Publisher message with parameters"""
+ pub = RealPublisher()
+ rec = Receiver(self)
+ # Three cases: 1. The parameter supplied by pub.issue_arg, 2.
+ # only the parameter given when connecting, 3. both
+ pub.Subscribe(PARAM, rec.with_params)
+ pub.Subscribe(SIMPLE, rec.with_params, "deliverator")
+ pub.Subscribe(PARAM, rec.with_params, "loglo")
+
+ pub.param_action()
+ pub.simple_action()
+ self.assertEquals(rec.messages, [("params", 42),
+ ("params", 42, "loglo"),
+ ("params", "deliverator")])
+
+ # make sure that all references have been deleted
+ pub.Destroy()
+ del rec
+ self.check_deletions()
+
+ def test_cyclic_references(self):
+ """Test whether Publisher avoids cyclic references"""
+ pub = RealPublisher()
+ rec = Receiver(self)
+ pub.Subscribe(SIMPLE, rec.no_params, ())
+
+ # deleting pub and rec should be enough that the last reference
+ # to rec has been dropped because the connector doesn't keep
+ # references to the publishers and SimplePublisher's __del__
+ # method removes all subscriptions
+ del pub
+ del rec
+ self.check_deletions()
+
+ def test_unsubscribe_after_destroy(self):
+ """Test that Unsubscribe() does not raise exceptions after a Destroy"""
+ pub = RealPublisher()
+ rec = Receiver(self)
+ pub.Subscribe(SIMPLE, rec.no_params)
+
+ # Sanity check: Issue a message and check whether the receiver
+ # got it
+ pub.simple_action()
+ self.assertEquals(rec.messages, [("no_params",)])
+ rec.reset()
+
+ # Now the real test. Destroy the publisher and Unsubscribe the
+ # receiver afterwards. The Unsubscribe should not raise an
+ # exception.
+ pub.Destroy()
+ try:
+ pub.Unsubscribe(SIMPLE, rec.no_params)
+ except ConnectorError:
+ self.fail("Unsubscribe after Destroy raised exception:\n"+
+ "".join(traceback.format_exception(*sys.exc_info())))
+
+
+class MyConduit(Conduit):
+
+ """Class for use in the Conduit tests
+
+ Like publishers Conduits are not instantiated themselves they're
+ always used as base classes.
+ """
+
+ def __init__(self, forward):
+ self.forward = forward
+ self.subscribe_forwarding(SIMPLE, self.forward)
+
+ def set_forward(self, forward):
+ # NOTE: The fact the we simply pass self.forward through to
+ # unsubscribe_forwarding and subscribe_forwarding is used by the
+ # test for None handling.
+ self.unsubscribe_forwarding(SIMPLE, self.forward)
+ self.forward = forward
+ self.subscribe_forwarding(SIMPLE, self.forward)
+
+ def action(self):
+ self.delegate.param_action()
+
+
+class TestConduit(unittest.TestCase, support.SubscriberMixin):
+
+ """Tests for the Conduit class"""
+
+ def setUp(self):
+ self.publisher = RealPublisher()
+ self.other_publisher = RealPublisher()
+ self.clear_messages()
+
+ def tearDown(self):
+ self.clear_messages()
+ self.publisher.Destroy()
+ self.other_publisher.Destroy()
+ self.publisher = self.other_publisher = None
+
+ def test_forwarding(self):
+ """Test conduit forwarding"""
+ cond = MyConduit(self.publisher)
+ cond.Subscribe(SIMPLE, self.subscribe_with_params, SIMPLE)
+ self.publisher.simple_action()
+ self.check_messages([(SIMPLE,)])
+ self.clear_messages()
+
+ # Set a different publisher. The message of the new publisher
+ # will be forwarded through the conduit but not that of the old
+ # one anymore
+ cond.set_forward(self.other_publisher)
+ self.other_publisher.simple_action()
+ self.check_messages([(SIMPLE,)])
+ self.clear_messages()
+
+ self.publisher.simple_action()
+ self.check_messages([])
+ self.clear_messages()
+
+ def test_none_handling(self):
+ """Test whether (un)subscribe_forwarding work with None"""
+ # All we test is whether it works without raising exceptions :)
+ cond = MyConduit(None)
+ cond.set_forward(None)
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_csv_table.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_csv_table.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_csv_table.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,78 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""
+Test the CSV table export
+"""
+
+__version__ = "$Revision"
+# $Source$
+# $Id: test_csv_table.py 1398 2003-07-10 14:55:49Z jonathan $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.table import MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
+ table_to_csv
+
+class TestCSVTable(unittest.TestCase, support.FileTestMixin):
+
+ def setUp(self):
+ """Create a simple table and write to file."""
+ self.table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 0.25, 100),
+ ("bar", 1e10, 17)])
+
+ def test_table_to_cvs(self):
+ """Test table_to_csv()"""
+ filename = self.temp_file_name("test_export_csv.csv")
+ table_to_csv(self.table, filename)
+ file = open(filename, "r")
+
+ # Tile line
+ line=file.readline()
+ self.assertEquals(line,'#type,value,code\n')
+
+ # Data lines
+ line=file.readline()
+ self.assertEquals(line,'UNKNOWN,0.0,0\n')
+
+ line=file.readline()
+ self.assertEquals(line,'Foo,0.5,-1\n')
+
+ line=file.readline()
+ self.assertEquals(line,'Foo,0.25,100\n')
+
+ line=file.readline()
+ self.assertEquals(line,'bar,10000000000.0,17\n')
+ self.assertEquals(file.readline(),'')
+
+ # save selected records
+ table_to_csv(self.table, filename, [1, 3])
+ file = open(filename, "r")
+
+ # Tile line
+ line=file.readline()
+ self.assertEquals(line,'#type,value,code\n')
+
+ # Data lines
+ line=file.readline()
+ self.assertEquals(line,'Foo,0.5,-1\n')
+
+ line=file.readline()
+ self.assertEquals(line,'bar,10000000000.0,17\n')
+ self.assertEquals(file.readline(),'')
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_dbf_table.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_dbf_table.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_dbf_table.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,257 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the DBFTable class
+"""
+
+__version__ = "$Revision: 1662 $"
+# $Source$
+# $Id: test_dbf_table.py 1662 2003-08-27 13:51:01Z bh $
+
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.table import DBFTable, MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
+ table_to_dbf
+import dbflib
+
+class TestTableToDBF(unittest.TestCase, support.FileTestMixin):
+
+ def test_table_to_dbf(self):
+ """Test table_to_dbf"""
+ memtable = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 1.0/256, 100),
+ ("bar", 1e10, 17)])
+
+ filename = self.temp_file_name("test_table_to_dbf.dbf")
+ table_to_dbf(memtable, filename)
+
+ dbf = dbflib.DBFFile(filename)
+ self.assertEquals(dbf.read_record(2),
+ {'code': 100, 'type': 'Foo', 'value': 0.00390625})
+ self.assertEquals(dbf.field_count(), 3)
+ self.assertEquals(dbf.record_count(), 4)
+ self.assertEquals(dbf.field_info(0),
+ (dbflib.FTString, "type", 7, 0))
+ self.assertEquals(dbf.field_info(1),
+ (dbflib.FTDouble, "value", 24, 12))
+ self.assertEquals(dbf.field_info(2),
+ (dbflib.FTInteger, "code", 3, 0))
+
+ # save selected rows
+ table_to_dbf(memtable, filename, [1, 3])
+
+ dbf = dbflib.DBFFile(filename)
+ self.assertEquals(dbf.read_record(0),
+ {'code': -1, 'type': 'Foo', 'value': 0.5})
+ self.assertEquals(dbf.field_count(), 3)
+ self.assertEquals(dbf.record_count(), 2)
+ self.assertEquals(dbf.field_info(0),
+ (dbflib.FTString, "type", 7, 0))
+ self.assertEquals(dbf.field_info(1),
+ (dbflib.FTDouble, "value", 24, 12))
+ self.assertEquals(dbf.field_info(2),
+ (dbflib.FTInteger, "code", 3, 0))
+
+ def test_table_to_dbf_long_col_names(self):
+ """Test table_to_dbf with long column names."""
+ memtable = MemoryTable([("SOME_STRING", FIELDTYPE_STRING),
+ ("SOME_LONG_COLNAME", FIELDTYPE_DOUBLE),
+ ("SOME_LONG_COLNAME_2", FIELDTYPE_DOUBLE)],
+ [("UNKNOWN", 0.0, 0.0),
+ ("Foo", 1.0, 0.0),
+ ("Foo", 478.23482182999999, 0.0),
+ ("bar", -2.25, 1.0)])
+
+ filename = self.temp_file_name("test_table_to_dbf_long_col_names.dbf")
+ table_to_dbf(memtable, filename)
+
+ dbf = dbflib.DBFFile(filename)
+ self.assertEquals(dbf.read_record(3),
+ {'SOME_STRIN': "bar", 'SOME_LONG_': -2.25,
+ 'SOME_LONG1': 1.0})
+
+class TestDBFTable(unittest.TestCase, support.FileTestMixin):
+
+ def setUp(self):
+ """Create a new dbf file. The name is in self.filename"""
+ simple = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 0.25, 100),
+ ("bar", 1e10, 17)])
+
+ self.filename = self.temp_file_name("test_dbf_read.dbf")
+ table_to_dbf(simple, self.filename)
+
+ def test_num_rows(self):
+ """Test DBFTable.NumRows()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.NumRows(), 4)
+
+ def test_num_columns(self):
+ """Test DBFTable.NumColumns()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.NumColumns(), 3)
+
+ def test_columns(self):
+ """Test DBFTable.Columns()"""
+ table = DBFTable(self.filename)
+ columns = table.Columns()
+ self.assertEquals(columns[0].name, "type")
+ self.assertEquals(columns[0].type, FIELDTYPE_STRING)
+ self.assertEquals(columns[1].name, "value")
+ self.assertEquals(columns[1].type, FIELDTYPE_DOUBLE)
+ self.assertEquals(columns[2].name, "code")
+ self.assertEquals(columns[2].type, FIELDTYPE_INT)
+
+ def test_column(self):
+ """Test DBFTable.Column()"""
+ table = DBFTable(self.filename)
+ # The Column method can be called with either an index or a name
+ col = table.Column(2)
+ self.assertEquals(col.name, "code")
+ self.assertEquals(col.type, FIELDTYPE_INT)
+ col = table.Column("value")
+ self.assertEquals(col.name, "value")
+ self.assertEquals(col.type, FIELDTYPE_DOUBLE)
+
+ def test_has_column(self):
+ """Test DBFTable.HasColumn()"""
+ table = DBFTable(self.filename)
+ # HasColumn
+ self.failUnless(table.HasColumn("value"))
+ self.failUnless(table.HasColumn(2))
+ # HasColumn for non-exisiting columns
+ self.failIf(table.HasColumn("non_existing_name"))
+ self.failIf(table.HasColumn(100))
+
+ def test_read_row_as_dict(self):
+ """Test DBFTable.ReadRowAsDict()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.ReadRowAsDict(1),
+ {"type": "Foo", "value": 0.5, "code": -1})
+
+ def test_read_row_as_dict_row_count_mode(self):
+ """Test DBFTable.ReadRowAsDict() row count address mode"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.ReadRowAsDict(1, row_is_ordinal = 1),
+ {"type": "Foo", "value": 0.5, "code": -1})
+
+ def test_read_value(self):
+ """Test DBFTable.ReadValue()"""
+ table = DBFTable(self.filename)
+ # The column in ReadValue may be given as either name or index
+ self.assertEquals(table.ReadValue(2, 0), "Foo")
+ self.assertEquals(table.ReadValue(3, "code"), 17)
+
+ def test_read_value_row_count_mode(self):
+ """Test DBFTable.ReadValue() row count address mode"""
+ table = DBFTable(self.filename)
+ # The column in ReadValue may be given as either name or index
+ self.assertEquals(table.ReadValue(2, 0, row_is_ordinal = 1), "Foo")
+ self.assertEquals(table.ReadValue(3, "code", row_is_ordinal = 1), 17)
+
+ def test_row_id_to_ordinal(self):
+ """Test DBFTable.RowIdToOrdinal()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.RowIdToOrdinal(5), 5)
+
+ def test_row_oridnal_to_id(self):
+ """Test DBFTable.RowOrdinalToId()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.RowOrdinalToId(5), 5)
+
+ def test_value_range(self):
+ """Test DBFTable.ValueRange()"""
+ table = DBFTable(self.filename)
+ self.assertEquals(table.ValueRange("code"), (-1, 100))
+ self.assertEquals(table.ValueRange(1), (0, 1e10))
+
+ def test_unique_values(self):
+ """Test DBFTable.UniqueValues()"""
+ table = DBFTable(self.filename)
+
+ # The column can be specified by name or index
+ self.assertEquals(table.UniqueValues("type"),
+ ["Foo", "UNKNOWN", "bar"])
+ self.assertEquals(table.UniqueValues(2), [-1, 0, 17, 100])
+
+ def test_dependencies(self):
+ """Test DBFTable.Dependencies()"""
+ # A DBFTable doesn't have dependencies
+ table = DBFTable(self.filename)
+ self.assertEquals(len(table.Dependencies()), 0)
+
+ def test_filename(self):
+ """Test DBFTable.FileName()"""
+ # A DBFTable doesn't have dependencies
+ table = DBFTable(self.filename)
+ self.assertEquals(table.FileName(), self.filename)
+
+ def test_title(self):
+ """Test DBFTable.Title()"""
+ # A DBFTable doesn't have dependencies
+ table = DBFTable(self.filename)
+ self.assertEquals(table.Title(), "test_dbf_read")
+
+
+class TestDBFTableWriting(unittest.TestCase, support.FileTestMixin):
+
+ def test_write(self):
+ """Test DBFTable.write_record()"""
+ eq = self.assertEquals
+
+ # First create a DBF file
+ dbffilename = self.temp_file_name("dbftable_write.dbf")
+ dbf = dbflib.create(dbffilename)
+ dbf.add_field("NAME", dbflib.FTString, 20, 0)
+ dbf.add_field("INT", dbflib.FTInteger, 10, 0)
+ dbf.add_field("FLOAT", dbflib.FTDouble, 10, 4)
+ dbf.write_record(0, {'NAME': "Weatherwax", "INT":1,
+ "FLOAT":3.1415926535})
+ dbf.close()
+
+ # Create the table
+ table = DBFTable(dbffilename)
+ record = table.ReadRowAsDict(0)
+ # The FLOAT value is different from above because of rounding
+ eq(record, {'NAME': "Weatherwax", "INT":1, "FLOAT":3.1415999999999999})
+
+ # change only one field
+ table.write_record(0, {"NAME": "Ogg"})
+ # check whether it has been written immediately
+ dbf = dbflib.DBFFile(dbffilename)
+ control = dbf.read_record(0)
+ eq(control, {'NAME': "Ogg", "INT":1, "FLOAT":3.1415999999999999})
+ dbf.close()
+
+ # check whether the table itself returns the new value
+ eq(table.ReadRowAsDict(0),
+ {'NAME': "Ogg", "INT":1, "FLOAT":3.1415999999999999})
+
+ # Check whether we can specify the record as a tuple
+ table.write_record(0, ("Garlick", 2, 1.5))
+ eq(table.ReadRowAsDict(0), {"NAME": "Garlick", "INT": 2, "FLOAT": 1.5})
+
+ table.Destroy()
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_derivedshapestore.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_derivedshapestore.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_derivedshapestore.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,130 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Tests for DerivedShapeStore"""
+
+__version__ = "$Revision: 1784 $"
+# $Source$
+# $Id: test_derivedshapestore.py 1784 2003-10-07 17:17:22Z bh $
+
+import os
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.data import DerivedShapeStore, ShapefileStore, \
+ SHAPETYPE_ARC, RAW_SHAPEFILE
+
+from Thuban.Model.session import Session
+from Thuban.Model.table import MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
+
+
+class TestDerivedShapeStore(unittest.TestCase, support.FloatComparisonMixin):
+
+ def setUp(self):
+ """Initialize self.session"""
+ self.session = Session("Test Session")
+ self.filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ self.store = ShapefileStore(self.session, self.filename)
+
+ self.table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0)] * 839)
+ self.derived = DerivedShapeStore(self.store, self.table)
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_dependencies(self):
+ """Test DerivedShapeStore dependencies"""
+ # The shapestore itself depends on nothing else
+ self.assertEquals(self.derived.Dependencies(),
+ (self.store, self.table))
+
+ def test_orig_shapestore(self):
+ """Test DerivedShapeStore.OrigShapeStore()"""
+ self.assertEquals(self.derived.OrigShapeStore(), self.store)
+
+ def test_shape_type(self):
+ """Test DerivedShapeStore.ShapeType() with arc shapes"""
+ self.assertEquals(self.derived.ShapeType(), SHAPETYPE_ARC)
+
+ def test_raw_format(self):
+ """Test DerivedShapeStore.RawShapeFormat() with shapefiles"""
+ self.assertEquals(self.derived.RawShapeFormat(), RAW_SHAPEFILE)
+
+ def test_boundingbox(self):
+ """Test DerivedShapeStore.BoundingBox() with arc shapes"""
+ self.assertFloatSeqEqual(self.derived.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+
+ def test_num_shapes(self):
+ """Test DerivedShapeStore.NumShapes() with arc shapes"""
+ self.assertEquals(self.derived.NumShapes(), 839)
+
+ def test_shapes_in_region(self):
+ """Test DerivedShapeStore.ShapesInRegion() with arc shapes"""
+ shapes = self.derived.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [613, 726, 838])
+
+ def test_all_shapes(self):
+ """Test DerivedShapeStore.AllShapes()"""
+ self.assertEquals([s.ShapeID() for s in self.store.AllShapes()],
+ range(self.store.NumShapes()))
+
+ def test_shape(self):
+ """Test DerivedShapeStore.Shape() with arc shapes"""
+ self.assertPointListEquals(self.derived.Shape(32).Points(),
+ [[(-15.08217430114746, 66.2773818969726),
+ (-15.02635002136230, 66.2733917236328)]])
+ def test_shape_shapeid(self):
+ """Test DerivedShapeStore.Shape(i).ShapeID()"""
+ self.assertEquals(self.store.Shape(5).ShapeID(), 5)
+
+
+
+class TestDerivedShapeStoreExceptions(unittest.TestCase):
+
+ """Test DerivedShapeStore exceptions"""
+
+ def tearDown(self):
+ if hasattr(self, "session"):
+ self.session.Destroy()
+ self.session = None
+
+ def test_table_with_wrong_size(self):
+ """Test DerivedShapeStore() with a table with the wrong number of lines
+ """
+ filename = os.path.join("..", "Data", "iceland", "roads-line.shp")
+ session = self.session = Session("TestDerivedShapeStore Session")
+ store = session.OpenShapefile(filename)
+
+ table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 0.25, 100),
+ ("bar", 1e10, 17)])
+
+ # Trying to create a DerivedShapeStore where the number of lines
+ # in the table is not the same as the number of shapes in the
+ # shapefile raises a ValueError
+ self.assertRaises(ValueError, DerivedShapeStore, store, table)
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_export.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_export.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_export.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,57 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Thuban export calculations
+"""
+
+__version__ = "$Revision: 1454 $"
+# $Source$
+# $Id: test_export.py 1454 2003-07-18 14:41:04Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.UI.viewport import output_transform
+
+class TestScalebar(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Test cases for the Thuban export calculations
+ """
+
+ def test_output_transform(self):
+ """Test output_transform()."""
+
+ scale, offset, mapregion = output_transform(1.0, (0,0),
+ (200, 100), (200, 100))
+ self.assertFloatEqual(0.3, scale)
+ self.assertFloatSeqEqual((0.0, 0.0), offset)
+ self.assertFloatSeqEqual((20.0, 20.0, 80.0, 80.0), mapregion)
+
+ scale, offset, mapregion = output_transform(1.0, (0,0),
+ (200, 100), (100, 200))
+ self.assertFloatEqual(0.16, scale)
+ self.assertFloatSeqEqual((0.0, 0.0), offset)
+ self.assertFloatSeqEqual((20.0, 20.0, 52.0, 52.0), mapregion)
+
+ scale, offset, mapregion = output_transform(1.0, (5,5),
+ (200, 100), (100, 100))
+ self.assertFloatEqual(0.16, scale)
+ self.assertFloatSeqEqual((0.8, 0.8), offset)
+ self.assertFloatSeqEqual((20.0, 20.0, 52.0, 52.0), mapregion)
+
+ scale, offset, mapregion = output_transform(1.0, (0,0),
+ (200, 100), (200, 200))
+ self.assertFloatEqual(0.52, scale)
+ self.assertFloatSeqEqual((0.0, 0.0), offset)
+ self.assertFloatSeqEqual((20, 20, 124.0, 124.0), mapregion)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_fileutil.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_fileutil.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_fileutil.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,67 @@
+# Copyright (c) 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the functions in Thuban.Lib.fileutil
+"""
+
+__version__ = "$Revision: 340 $"
+# $Source$
+# $Id: test_fileutil.py 340 2002-09-20 17:32:59Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Lib.fileutil import relative_filename_posix, relative_filename_nt
+
+class TestRelativeFilename(unittest.TestCase):
+
+ """Test cases for the relative_filename function."""
+
+ def test_posix(self):
+ """Test relative_filename posix version"""
+ self.assertEquals(relative_filename_posix("/usr/local/lib/",
+ "/usr/local/lib/python"),
+ 'python')
+ self.assertEquals(relative_filename_posix("/usr/local/lib/",
+ "/usr/local/bin/python"),
+ '../bin/python')
+ self.assertEquals(relative_filename_posix("/usr/local/lib/",
+ "/usr/bin/python"),
+ '../../bin/python')
+ self.assertEquals(relative_filename_posix("/usr/local/lib/",
+ "/var/spool/mail"),
+ '/var/spool/mail')
+ self.assertEquals(relative_filename_posix("/home/", "xyzzy"),
+ 'xyzzy')
+ self.assertRaises(TypeError,
+ relative_filename_posix, "home/", "/xyzzy")
+
+ def test_nt(self):
+ """Test relative_filename nt version"""
+ self.assertEquals(relative_filename_nt(r"C:\Programme\Python",
+ r"C:\Programme\Thuban"),
+ '..\\Thuban')
+ self.assertEquals(relative_filename_nt(r"C:\Programme\Python",
+ r"D:\Programme\Thuban"),
+ 'D:\\Programme\\Thuban')
+ self.assertEquals(relative_filename_nt(r"C:\Programme\Python",
+ r"C:Programme"),
+ 'C:Programme')
+ # first argument is not an absolute filename
+ self.assertRaises(TypeError, relative_filename_nt,
+ r"C:Programme\Python", r"C:Programme")
+ # No drive letters
+ self.assertRaises(TypeError, relative_filename_nt,
+ r"\Programme\Python", r"\Programme")
+
+
+if __name__ == "__main__":
+ unittest.main()
+
Added: packages/thuban/branches/upstream/current/test/test_hittest.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_hittest.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_hittest.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,149 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test Thuban.UI.hittest"""
+
+__version__ = "$Revision: 1589 $"
+# $Source$
+# $Id: test_hittest.py 1589 2003-08-15 12:49:08Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.UI.hittest import line_hit, polygon_hit, arc_hit
+
+
+class TestLineHit(unittest.TestCase):
+
+ def test_inside(self):
+ """Test line_hit with point that would be on the 'inside'
+
+ Inside here means that the point is to the right of the line but
+ not so close that the line itself is hit.
+ """
+ self.assertEquals(line_hit(0, 0, 10, 10, 20, 5), 1)
+ self.assertEquals(line_hit(10, 10, 0, 0, 20, 5), 1)
+ self.assertEquals(line_hit(10, 10, 0, 0, 8, 5), 1)
+
+ def test_outside(self):
+ """Test line_hit with point that would be on the 'outside'
+
+ Inside here means that the point is to the left of the line but
+ not so close that the line itself is hit.
+ """
+ self.assertEquals(line_hit(0, 0, 10, 10, -10, 5), 0)
+ self.assertEquals(line_hit(10, 10, 0, 0, -10, 5), 0)
+ self.assertEquals(line_hit(10, 10, 0, 0, 2, 5), 0)
+
+ def test_on_line(self):
+ """Test line_hit with point that would be on or near the line"""
+ self.assertEquals(line_hit(0, 0, 10, -10, 5, -5), -1)
+ self.assertEquals(line_hit(0, 0, 10, -10, 10, -10), -1)
+ self.assertEquals(line_hit(0, 0, 10, -10, 5, -6), -1)
+
+ def test_horizontal_line(self):
+ """Test line_hit with a horizontal line
+
+ For a horizonal line, line_hit will never return 1. It will
+ return -1 though for points close to or on the line.
+ """
+ self.assertEquals(line_hit(10, 10, 10, 10, -10, 10), 0)
+ self.assertEquals(line_hit(10, 10, 15, 10, 20, 10), 0)
+ self.assertEquals(line_hit(10, 10, 15, 10, 12, 10), -1)
+
+ # Hits near the line will also be counted as line hits.
+ self.assertEquals(line_hit(10, 10, 15, 10, 12, 11), -1)
+ self.assertEquals(line_hit(10, 10, 15, 10, 12, 9), -1)
+
+ def test_upper_ignored(self):
+ """Test line_hit with a point whose ray would hit the upper end point
+
+ The upper end point is not hit to avoid problems with hit
+ testing for polygons.
+ """
+ self.assertEquals(line_hit(-100, 20, 10, -10, 1000, 20), 0)
+ self.assertEquals(line_hit(10, -10, -100, 20, 1000, 20), 0)
+
+
+class TestPolygonHit(unittest.TestCase):
+
+ def test_simple_inside(self):
+ """Test polygon_hit with simple polygon and inside point"""
+ self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
+ (0, 0)]], 5, 5),
+ 1)
+
+ def test_simple_outside(self):
+ """Test polygon_hit with simple polygon and outside point"""
+ self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
+ (0, 0)]], 20, 5),
+ 0)
+ self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
+ (0, 0)]], 20, 100),
+ 0)
+
+ self.assertEquals(polygon_hit([[(0, 0), (10, 0), (10, 10), (0, 10),
+ (0, 0)]], 20, -10),
+ 0)
+
+ def test_holes_outside(self):
+ """Test polygon_hit with polygon with holes and outside point"""
+ points = [[(0, 0), (100, 0), (100, 100), (0, 100), (0, 0)],
+ [(20, 20), (80, 20), (80, 80), (20, 80), (20, 20)]]
+ self.assertEquals(polygon_hit(points, 50, 50), 0)
+ self.assertEquals(polygon_hit(points, 130, 50), 0)
+
+ def test_holes_inside(self):
+ """Test polygon_hit with polygon with holes and inside point"""
+ points = [[(0, 0), (100, 0), (100, 100), (0, 100), (0, 0)],
+ [(20, 20), (80, 20), (80, 80), (20, 80), (20, 20)]]
+ self.assertEquals(polygon_hit(points, 50, 90), 1)
+ self.assertEquals(polygon_hit(points, 90, 50), 1)
+ self.assertEquals(polygon_hit(points, 10, 50), 1)
+
+ def test_vertex(self):
+ """Test polygon_hit with simple polygon and point whose ray hits corner
+ """
+ points = [[(-10, -5), (-10, 20), (10, 50), (10, 0), (-10, -5)]]
+ self.assertEquals(polygon_hit(points, 0, 20), 1)
+
+ def test_border(self):
+ """Test polygon_hit with simple polygon and point on/near border"""
+ points = [[(-10, -5), (-10, 20), (10, 50), (10, 0), (-10, -5)]]
+ self.assertEquals(polygon_hit(points, -9, 20), -1)
+ self.assertEquals(polygon_hit(points, 0, -2), -1)
+ self.assertEquals(polygon_hit(points, 0, -4), -1)
+
+
+
+class TestArcHit(unittest.TestCase):
+
+ def test_simple_hit(self):
+ """Test arc_hit with simple arc and point on/near arc"""
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 5, 0), 1)
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 15, 16), 1)
+
+ def test_simple_not_hit(self):
+ """Test arc_hit with simple arc and point not on arc"""
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 5, 100), 0)
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 13, 7), 0)
+
+ def test_corner(self):
+ """Test arc_hit with point on/near arc's corner"""
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 11, 10), 1)
+ self.assertEquals(arc_hit([[(0, 0), (10, 0), (10, 10), (20, 20)]],
+ 15, 10), 0)
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_label.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_label.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_label.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,93 @@
+# Copyright (c) 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Label and LabelLayer classes
+"""
+
+__version__ = "$Revision: 330 $"
+# $Source$
+# $Id: test_label.py 330 2002-09-20 14:30:34Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.messages import CHANGED
+from Thuban.Model.label import Label, LabelLayer, \
+ ALIGN_CENTER, ALIGN_BASELINE, ALIGN_LEFT, ALIGN_TOP
+
+
+class TestLabel(unittest.TestCase):
+
+ """Test cases for the Label class"""
+
+ def test(self):
+ """Test Label"""
+ # The label objects are very simple. We just have to test
+ # whether instantiating one assigns the correct values to the
+ # instance variables
+ label = Label(10.5, 234567.0, "Label Text",
+ ALIGN_CENTER, ALIGN_BASELINE)
+ self.assertEquals(label.x, 10.5)
+ self.assertEquals(label.y, 234567.0)
+ self.assertEquals(label.text, "Label Text")
+ self.assertEquals(label.halign, ALIGN_CENTER)
+ self.assertEquals(label.valign, ALIGN_BASELINE)
+
+
+class TestLabelLayer(unittest.TestCase, support.SubscriberMixin):
+
+ """Test cases for LabelLayer"""
+
+ def setUp(self):
+ """Clear the messages list and create a LabelLayer as self.layer
+ """
+ self.clear_messages()
+ self.layer = LabelLayer("A Label Layer")
+ self.layer.Subscribe(CHANGED, self.subscribe_with_params, CHANGED)
+
+ def tearDown(self):
+ """Clear the messages list and explictly destroy self.layer"""
+ self.layer.Destroy()
+ self.clear_messages()
+
+ def test_initial_state(self):
+ """Test LabelLayer's initial state"""
+ self.failIf(self.layer.WasModified())
+ self.assertEquals(self.layer.Title(), "A Label Layer")
+ self.assertEquals(self.layer.Labels(), [])
+ self.check_messages([])
+
+ def test_methods(self):
+ """Test LabelLayer methods"""
+ # first add a label
+ self.layer.AddLabel(10.5, 234567.0, "Label Text")
+ self.check_messages([(CHANGED,)])
+ self.assertEquals(self.layer.Labels()[0].text, "Label Text")
+ self.assert_(self.layer.WasModified())
+
+ # add another one
+ self.layer.AddLabel(-1000.125, 987654.0, "Another Label",
+ ALIGN_LEFT, ALIGN_TOP)
+ self.check_messages([(CHANGED,),
+ (CHANGED,)])
+ self.assertEquals(self.layer.Labels()[0].text, "Label Text")
+ self.assertEquals(self.layer.Labels()[1].text, "Another Label")
+
+ # remove one
+ self.layer.RemoveLabel(0)
+ self.check_messages([(CHANGED,),
+ (CHANGED,),
+ (CHANGED,)])
+ self.assertEquals(self.layer.Labels()[0].text, "Another Label")
+
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_layer.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_layer.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_layer.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,536 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Layer class
+"""
+
+__version__ = "$Revision: 2688 $"
+# $Source$
+# $Id: test_layer.py 2688 2006-06-30 12:27:20Z frank $
+
+import os
+import unittest
+
+import mockgeo
+import support
+support.initthuban()
+
+import shapelib
+import dbflib
+
+from Thuban.Model.session import Session
+from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
+from Thuban.Model.messages import LAYER_LEGEND_CHANGED, \
+ LAYER_VISIBILITY_CHANGED, LAYER_SHAPESTORE_REPLACED, LAYER_CHANGED
+from Thuban.Model.table import FIELDTYPE_DOUBLE, FIELDTYPE_STRING, MemoryTable
+from Thuban.Model.proj import Projection
+from Thuban.Model.data import DerivedShapeStore
+from Thuban.Model.classification import Classification, ClassGroupSingleton, \
+ ClassGroupRange, ClassGroupPattern
+from Thuban.Model.color import Color
+
+import Thuban.Model.resource
+
+class TestLayer(unittest.TestCase, support.FileTestMixin,
+ support.FloatComparisonMixin):
+
+ """Test cases for different layer (shape) types"""
+
+ def setUp(self):
+ """Create a session self.session and initialize self.layer to None"""
+ self.session = Session("Test session for %s" % self.__class__)
+ self.layer = None
+
+ def tearDown(self):
+ """Call the layer's Destroy method and set session and layer to None"""
+ self.session.Destroy()
+ self.session = None
+ if self.layer is not None:
+ self.layer.Destroy()
+ self.layer = None
+
+ def build_path(self, filename):
+ return os.path.join("..", "Data", "iceland", filename)
+
+ def open_shapefile(self, filename):
+ """Open and return a shapestore for filename in the iceland data set"""
+ return self.session.OpenShapefile(self.build_path(filename))
+
+ def test_base_layer(self):
+ layer = self.layer = BaseLayer("Test BaseLayer")
+ self.assertEquals(layer.Title(), "Test BaseLayer")
+ self.failUnless(layer.Visible())
+
+ # toggle visibility
+ layer.SetVisible(False)
+ self.failIf(layer.Visible())
+
+ layer.SetVisible(True)
+ self.failUnless(layer.Visible())
+
+ self.failIf(layer.HasClassification())
+ self.failIf(layer.HasShapes())
+
+ self.assertEquals(layer.GetProjection(), None)
+
+ # set/get projection
+ proj = Projection(["proj=utm", "zone=26", "ellps=clrk66"])
+
+ layer.SetProjection(proj)
+ self.failUnless(layer.GetProjection() is proj)
+
+ # __init__ with other arguments
+ layer = BaseLayer("Test BaseLayer", False, proj)
+ self.failIf(layer.Visible())
+ self.failUnless(layer.GetProjection() is proj)
+
+ def test_arc_layer(self):
+ """Test Layer with arc shapes"""
+ layer = self.layer = Layer("Test Layer",
+ self.open_shapefile("roads-line.shp"))
+ self.failUnless(layer.HasClassification())
+ self.failUnless(layer.HasShapes())
+ self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
+ self.assertEquals(layer.NumShapes(), 839)
+ shape = layer.Shape(32)
+ self.assertPointListEquals(shape.Points(),
+ [[(-15.082174301147461, 66.27738189697265),
+ (-15.026350021362305, 66.27339172363281)]])
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+ shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [613, 726, 838])
+
+ self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
+ [-15.082174301147461, 66.27339172363281,
+ -15.026350021362305, 66.27738189697265])
+
+ shape = layer.Shape(33)
+ self.assertPointListEquals(shape.Points(),
+ [[(-22.24850654602050, 66.30645751953125),
+ (-22.23273086547851, 66.29407501220703),
+ (-22.23158073425293, 66.2876892089843),
+ (-22.24631881713867, 66.27006530761718)]])
+
+ self.assertFloatSeqEqual(layer.ShapesBoundingBox([32, 33]),
+ [-22.248506546020508, 66.270065307617188,
+ -15.026350021362305, 66.30645751953125])
+
+ self.assertEquals(layer.ShapesBoundingBox([]), None)
+ self.assertEquals(layer.ShapesBoundingBox(None), None)
+
+ def test_polygon_layer(self):
+ """Test Layer with polygon shapes"""
+ layer = self.layer = Layer("Test Layer",
+ self.open_shapefile("political.shp"))
+ self.failUnless(layer.HasClassification())
+ self.failUnless(layer.HasShapes())
+ self.assertEquals(layer.ShapeType(), SHAPETYPE_POLYGON)
+ self.assertEquals(layer.NumShapes(), 156)
+ shape = layer.Shape(4)
+ self.assertPointListEquals(shape.Points(),
+ [[(-22.40639114379882, 64.714111328125),
+ (-22.41621208190918, 64.7160034179687),
+ (-22.40605163574218, 64.719200134277),
+ (-22.40639114379882, 64.714111328125)]])
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ [-24.546524047851562, 63.286754608154297,
+ -13.495815277099609, 66.563774108886719])
+ shapes = layer.ShapesInRegion((-24.0, 64.0, -23.9, 64.1))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [91, 92, 144, 146, 148, 150, 152, 153])
+
+ def test_point_layer(self):
+ """Test Layer with point shapes"""
+ layer = self.layer = Layer("Test Layer",
+ self.open_shapefile("cultural_landmark-point.shp"))
+ self.failUnless(layer.HasClassification())
+ self.failUnless(layer.HasShapes())
+ self.assertEquals(layer.ShapeType(), SHAPETYPE_POINT)
+ self.assertEquals(layer.NumShapes(), 34)
+ shape = layer.Shape(0)
+ self.assertPointListEquals(shape.Points(),
+ [[(-22.711074829101562, 66.36572265625)]])
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ [-23.806047439575195, 63.405960083007812,
+ -15.12291431427002, 66.36572265625])
+ shapes = layer.ShapesInRegion((-24.0, 64.0, -23.80, 64.1))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [0, 1, 2, 3, 4, 5, 27, 28, 29, 30, 31])
+
+ def test_arc_layer_with_projection(self):
+ """Test Layer with point shapes and a projection"""
+ # We use mock data here so that we have precise control over the
+ # values
+ table = MemoryTable([("FOO", FIELDTYPE_STRING)], [("bla",)])
+ store = mockgeo.SimpleShapeStore(SHAPETYPE_ARC,
+ [[[(9884828.7209840547, 5607720.9774499247),
+ (11298336.04640449, 9287823.2044059951)]]],
+ table)
+ layer = self.layer = Layer("Test Layer", store)
+
+ proj = Projection(["proj=lcc", "lon_0=0", "lat_1=20n", "lat_2=60n",
+ "ellps=clrk66"])
+ layer.SetProjection(proj)
+
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ (9884828.7209840547, 5607720.9774499247,
+ 11298336.04640449, 9287823.2044059951))
+ self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
+ (90.0, -8.90043373, 120, 11.1616263))
+ shapes = layer.ShapesInRegion((100, -10, 150, +10))
+ self.assertEquals([s.ShapeID() for s in shapes], [0])
+ self.assertFloatSeqEqual(layer.ShapesBoundingBox([0]),
+ (90.0, -8.90043373, 120, 11.1616263))
+
+ # Test a very large bounding box in the query. Naive inverse
+ # projection will create infs instead of proper coordinate
+ # values and a different result (an empty list instead of [0])
+ shapes = layer.ShapesInRegion((-180, -170, 200, +120))
+ self.assertEquals([s.ShapeID() for s in shapes],[0])
+
+ def test_empty_layer(self):
+ """Test Layer with empty shape file"""
+ # create an empty shape file
+ shapefilename = self.temp_file_name("layer_empty.shp")
+ shp = shapelib.create(shapefilename, shapelib.SHPT_POLYGON)
+ shp.close()
+ # create an empty DBF file too because Thuban can't cope yet
+ # with missing DBF file.
+ dbffilename = self.temp_file_name("layer_empty.dbf")
+ dbf = dbflib.create(dbffilename)
+ dbf.add_field("NAME", dbflib.FTString, 20, 0)
+ dbf.close()
+
+ # Now try to open it.
+ layer = self.layer = Layer("Empty Layer",
+ self.session.OpenShapefile(shapefilename))
+ self.assertEquals(layer.BoundingBox(), None)
+ self.assertEquals(layer.LatLongBoundingBox(), None)
+ self.assertEquals(layer.NumShapes(), 0)
+
+ def test_get_field_type(self):
+ """Test Layer.GetFieldType()"""
+ layer = self.layer = Layer("Test Layer",
+ self.open_shapefile("roads-line.shp"))
+ self.assertEquals(layer.GetFieldType("LENGTH"), FIELDTYPE_DOUBLE)
+ self.assertEquals(layer.GetFieldType("non existing"), None)
+
+ def test_raster_layer(self):
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+ filename = self.build_path("island.tif")
+ layer = RasterLayer("Test RasterLayer", filename)
+ self.failIf(layer.HasClassification())
+ self.failIf(layer.HasShapes())
+ self.assertEquals(layer.MaskType(), layer.MASK_BIT)
+ self.assertEquals(layer.GetImageFilename(), os.path.abspath(filename))
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ [-24.5500000, 63.2833330,
+ -13.4916670, 66.5666670])
+ self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
+ [-24.5500000, 63.2833330,
+ -13.4916670, 66.5666670])
+
+ info = layer.ImageInfo()
+ self.failIf(info is None)
+ self.failUnless(info.has_key("nBands"))
+ self.failUnless(info.has_key("Size"))
+ self.failUnless(info.has_key("Driver"))
+ self.failUnless(info.has_key("BandData"))
+
+ self.assertEquals(info["nBands"], 1)
+ self.assertEquals(info["Size"], (5002, 394))
+ self.assertEquals(info["Driver"], "GTiff")
+ self.assertEquals(info["BandData"], [(0.0, 140.0)])
+
+ def test_derived_store(self):
+ """Test layer with derived store"""
+ layer = self.layer = Layer("Test Layer",
+ self.open_shapefile("roads-line.shp"))
+ try:
+ store = layer.ShapeStore()
+ derived = DerivedShapeStore(store, store.Table())
+ layer.SetShapeStore(derived)
+ self.assert_(layer.ShapeStore() is derived)
+
+ self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
+ self.assertEquals(layer.NumShapes(), 839)
+ shape = layer.Shape(32)
+ self.assertPointListEquals(shape.Points(),
+ [[(-15.082174301147, 66.277381896972),
+ (-15.026350021362, 66.273391723632)]])
+ self.assertFloatSeqEqual(layer.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+ shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [613, 726, 838])
+
+ self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
+ [-15.082174301147461, 66.27339172363281,
+ -15.026350021362305, 66.27738189697265])
+
+ finally:
+ store = derived = None
+
+
+class SetShapeStoreTests(unittest.TestCase, support.SubscriberMixin):
+
+ def setUp(self):
+ """Create a layer with a classification as self.layer"""
+ self.clear_messages()
+ self.session = Session("Test session for %s" % self.__class__)
+ self.shapefilename = os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.dbf")
+ self.store = self.session.OpenShapefile(self.shapefilename)
+ self.layer = Layer("test layer", self.store)
+ self.classification = Classification()
+ self.classification.AppendGroup(ClassGroupSingleton("FARM"))
+ self.layer.SetClassificationColumn("CLPTLABEL")
+ self.layer.SetClassification(self.classification)
+ self.layer.UnsetModified()
+ self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
+ self.subscribe_with_params,
+ LAYER_SHAPESTORE_REPLACED)
+ self.layer.Subscribe(LAYER_CHANGED,
+ self.subscribe_with_params, LAYER_CHANGED)
+
+ def tearDown(self):
+ self.clear_messages()
+ self.layer.Destroy()
+ self.session.Destroy()
+ self.session = self.layer = self.store = self.classification = None
+
+ def test_sanity(self):
+ """SetShapeStoreTests sanity check
+
+ Test the initial state of the test case instances after setUp.
+ """
+ cls = self.layer.GetClassification()
+ self.assert_(cls is self.classification)
+ field = self.layer.GetClassificationColumn()
+ self.assertEquals(field, "CLPTLABEL")
+ self.assertEquals(self.layer.GetFieldType(field), FIELDTYPE_STRING)
+ self.assertEquals(self.layer.GetClassification().GetNumGroups(), 1)
+ self.failIf(self.layer.WasModified())
+
+ def test_set_shape_store_modified_flag(self):
+ """Test whether Layer.SetShapeStore() sets the modified flag"""
+ memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
+ [("bla",)] * self.layer.ShapeStore().Table().NumRows())
+ self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
+
+ self.assert_(self.layer.WasModified())
+
+ def test_set_shape_store_different_field_name(self):
+ """Test Layer.SetShapeStore() with different column name"""
+ memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
+ [("bla",)] * self.layer.ShapeStore().Table().NumRows())
+ self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
+ # The classification should contain only the default group now.
+ self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
+ self.check_messages([(self.layer, LAYER_CHANGED),
+ (self.layer, LAYER_SHAPESTORE_REPLACED)])
+
+ def test_set_shape_store_same_field(self):
+ """Test Layer.SetShapeStore() with same column name and type"""
+ memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_STRING)],
+ [("bla",)] * self.layer.ShapeStore().Table().NumRows())
+ self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
+ # The classification should be the same as before
+ self.assert_(self.layer.GetClassification() is self.classification)
+ self.check_messages([(self.layer, LAYER_SHAPESTORE_REPLACED)])
+
+ def test_set_shape_store_same_field_different_type(self):
+ """Test Layer.SetShapeStore() with same column name but different type
+ """
+ memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_DOUBLE)],
+ [(0.0,)] * self.layer.ShapeStore().Table().NumRows())
+ self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
+ # The classification should contain only the default group now.
+ self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
+ self.check_messages([(self.layer, LAYER_CHANGED),
+ (self.layer, LAYER_SHAPESTORE_REPLACED)])
+
+
+class TestLayerModification(unittest.TestCase, support.SubscriberMixin):
+
+ """Test cases for Layer method that modify the layer.
+ """
+
+ def setUp(self):
+ """Clear the list of received messages and create a layer and a session
+
+ The layer is bound to self.layer and the session to self.session.
+ """
+ self.clear_messages()
+ self.session = Session("Test session for %s" % self.__class__)
+ self.filename = os.path.join("..", "Data", "iceland", "political.shp")
+ self.layer = Layer("Test Layer",
+ self.session.OpenShapefile(self.filename))
+ self.layer.Subscribe(LAYER_LEGEND_CHANGED, self.subscribe_with_params,
+ LAYER_LEGEND_CHANGED)
+ self.layer.Subscribe(LAYER_VISIBILITY_CHANGED,
+ self.subscribe_with_params,
+ LAYER_VISIBILITY_CHANGED)
+ self.layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
+ LAYER_CHANGED)
+
+ def tearDown(self):
+ """Clear the list of received messages and explictly destroy self.layer
+ """
+ self.layer.Destroy()
+ self.layer = None
+ self.session.Destroy()
+ self.session = None
+ self.clear_messages()
+
+ def build_path(self, filename):
+ return os.path.join("..", "Data", "iceland", filename)
+
+ def test_sanity(self):
+ """TestLayerModification Sanity Checks"""
+ # test default settings
+ self.failIf(self.layer.WasModified())
+ self.assertEquals(self.layer.Visible(), 1)
+ # no messages should have been produced
+ self.check_messages([])
+
+ def test_visibility(self):
+ """Test Layer visibility"""
+ self.layer.SetVisible(0)
+ self.assertEquals(self.layer.Visible(), 0)
+ self.check_messages([(self.layer, LAYER_VISIBILITY_CHANGED)])
+
+ # currently, modifying the visibility doesn't count as changing
+ # the layer.
+ self.failIf(self.layer.WasModified())
+
+ def test_set_classification_numerical(self):
+ """Test Layer.SetClassification numerical"""
+ classification = Classification()
+ classification.AppendGroup(ClassGroupRange((0.0, 0.1)))
+
+ self.layer.SetClassification(classification)
+ self.layer.SetClassificationColumn("AREA")
+
+ self.check_messages([(self.layer, LAYER_CHANGED),
+ (self.layer, LAYER_CHANGED)])
+ self.failUnless(self.layer.WasModified())
+
+ self.clear_messages()
+ self.layer.UnsetModified()
+
+ # change only the classification column. This should issue a
+ # LAYER_CHANGED message as well.
+ self.layer.SetClassificationColumn("PERIMETER")
+
+ self.check_messages([(self.layer, LAYER_CHANGED)])
+ self.failUnless(self.layer.WasModified())
+
+ def test_set_classification_textual(self):
+ """Test Layer.SetClassification textual"""
+ classification = Classification()
+ classification.AppendGroup(ClassGroupPattern("I"))
+
+ self.layer.SetClassification(classification)
+ self.layer.SetClassificationColumn("POPYCOUN")
+
+ self.check_messages([(self.layer, LAYER_CHANGED),
+ (self.layer, LAYER_CHANGED)])
+ self.failUnless(self.layer.WasModified())
+
+ self.clear_messages()
+ self.layer.UnsetModified()
+
+ # change only the classification column. This should issue a
+ # LAYER_CHANGED message as well.
+ self.layer.SetClassificationColumn("POPYREG")
+
+ self.check_messages([(self.layer, LAYER_CHANGED)])
+ self.failUnless(self.layer.WasModified())
+
+
+ def test_tree_info(self):
+ """Test Layer.TreeInfo"""
+ self.assertEquals(self.layer.TreeInfo(),
+ ("Layer 'Test Layer'",
+ ['Filename: %s' % os.path.abspath(self.filename),
+ 'Shown',
+ 'Shapes: 156',
+ 'Extent (lat-lon): (-24.5465, 63.2868, -13.4958, 66.5638)',
+ 'Shapetype: Polygon',
+ self.layer.GetClassification()]))
+
+ def test_raster_layer(self):
+ if not Thuban.Model.resource.has_gdal_support():
+ raise support.SkipTest("No gdal support")
+
+
+ filename = self.build_path("island.tif")
+ layer = RasterLayer("Test RasterLayer", filename)
+
+ layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
+ LAYER_CHANGED)
+
+ self.assertEquals(layer.MaskType(), layer.MASK_BIT)
+
+ layer.SetMaskType(layer.MASK_NONE)
+ self.failIf(layer.MaskType() != layer.MASK_NONE)
+ self.check_messages([(layer, LAYER_CHANGED)])
+ self.clear_messages()
+
+ layer.SetMaskType(layer.MASK_NONE)
+ self.failIf(layer.MaskType() != layer.MASK_NONE)
+ self.check_messages([])
+ self.clear_messages()
+
+ layer.SetMaskType(layer.MASK_BIT)
+ self.failIf(layer.MaskType() != layer.MASK_BIT)
+ self.check_messages([(layer, LAYER_CHANGED)])
+ self.clear_messages()
+
+ layer.SetMaskType(layer.MASK_BIT)
+ self.failIf(layer.MaskType() != layer.MASK_BIT)
+ self.check_messages([])
+ self.clear_messages()
+
+ layer.SetMaskType(layer.MASK_ALPHA)
+ self.failIf(layer.MaskType() != layer.MASK_ALPHA)
+
+ layer.SetOpacity(0)
+ self.assertEquals(layer.Opacity(), 0)
+ layer.SetOpacity(0.5)
+ self.assertEquals(layer.Opacity(), 0.5)
+
+ self.clear_messages()
+ layer.SetOpacity(1)
+ self.assertEquals(layer.Opacity(), 1)
+ self.check_messages([(layer, LAYER_CHANGED)])
+ self.clear_messages()
+
+ self.assertRaises(ValueError, layer.SetOpacity, -0.1)
+ self.assertRaises(ValueError, layer.SetOpacity, 1.1)
+
+ layer.SetMaskType(layer.MASK_NONE)
+ self.clear_messages()
+ self.assertEquals(layer.Opacity(), 1)
+ self.check_messages([])
+ self.clear_messages()
+
+ self.assertRaises(ValueError, layer.SetMaskType, -1)
+ self.assertRaises(ValueError, layer.SetMaskType, 4)
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_lib_version.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_lib_version.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_lib_version.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,33 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+""""""
+
+__version__ = "$Revision: 2011 $"
+# $Source$
+# $Id: test_lib_version.py 2011 2003-12-03 09:46:27Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Lib.version import make_tuple
+
+
+class TestMakeTuple(unittest.TestCase):
+
+ def test(self):
+ """Test Thuban.version.make_tuple()"""
+ self.assertEquals(make_tuple("1.2"), (1, 2))
+ self.assertEquals(make_tuple("1.2.3"), (1, 2, 3))
+ self.assertEquals(make_tuple("2.4.0.7"), (2, 4, 0))
+ self.assertEquals(make_tuple("1.2+cvs.20031111"), (1, 2))
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_load.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_load.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_load.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,1161 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test loading a thuban session from a file
+
+The tests in this file (test_load.py) are always be the tests for the
+current version of the thuban file format. Tests for older versions can
+be found in the version specific test modules, e.g. test_load_0_2 for
+files created by Thuban 0.2.
+
+Maintenance of the test cases:
+
+When during a development period the file format is changed with respect
+to the last released version for the first time, the tests here should
+be copied to the version specific test file. The round-trip tests which
+save the session again and compare the XML files should not be copied
+over as they only make sense here to make sure th that the files checked
+here are actually ones that may have been written by the current thuban
+version.
+"""
+
+__version__ = "$Revision: 2688 $"
+# $Source$
+# $Id: test_load.py 2688 2006-06-30 12:27:20Z frank $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import postgissupport
+from xmlsupport import sax_eventlist
+
+import dbflib
+import shapelib
+
+from Thuban import internal_from_unicode
+from Thuban.Model.save import save_session
+from Thuban.Model.load import load_session, parse_color, LoadError, \
+ LoadCancelled
+from Thuban.Model.color import Transparent
+from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
+ ClassGroupSingleton, ClassGroupPattern, ClassGroupDefault
+from Thuban.Model.postgisdb import ConnectionError
+from Thuban.Model.table import DBFTable, MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
+ table_to_dbf
+from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
+ ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
+
+def filenames_equal(name1, name2):
+ """Return true if the filenames name1 and name2 are equal.
+
+ On systems where it is available, simply use os.path.samefile,
+ otherwise return whether the normalized versions of the filenames
+ according to os.path.normpath are equal.
+ """
+ if hasattr(os.path, "samefile"):
+ return os.path.samefile(name1, name2)
+ return os.path.normpath(name1) == os.path.normpath(name2)
+
+
+
+class LoadSessionTest(support.FileLoadTestCase):
+
+ """Base class for .thuban file loading tests
+
+ Basically the same as the FileLoadTestCase, except that all tests
+ use the '.thuban' extension by default and that setUp and tearDown
+ handle sessions.
+ """
+
+ file_extension = ".thuban"
+
+ def setUp(self):
+ """Create the test files"""
+ support.FileLoadTestCase.setUp(self)
+ self.session = None
+
+ def tearDown(self):
+ if self.session is not None:
+ self.session.Destroy()
+ self.session = None
+
+
+ dtd = "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ thubanids = [((dtd, n), (None, "id")) for n in
+ ["fileshapesource", "filetable", "jointable",
+ "derivedshapesource"]]
+ thubanidrefs = [((dtd, n), (None, m)) for n, m in
+ [("layer", "shapestore"),
+ ("jointable", "left"),
+ ("jointable", "right"),
+ ("derivedshapesource", "table"),
+ ("derivedshapesource", "shapesource")]]
+
+ # The filenames in the tests should be understandable on all
+ # currently supported platforms so filenames is an empty list
+ filenames = []
+
+ del n, m, dtd
+
+ def check_format(self):
+ """Check whether the file we loaded from matches the one that
+ would be written. Call this from each test case after loading
+ the session
+ """
+ filename = self.temp_file_name(self.id() + ".roundtrip.thuban")
+ save_session(self.session, filename)
+ el1 = sax_eventlist(filename = filename, ids = self.thubanids,
+ idrefs = self.thubanidrefs,
+ filenames = self.filenames)
+ el2 = sax_eventlist(filename = self.filename(), ids = self.thubanids,
+ idrefs = self.thubanidrefs,
+ filenames = self.filenames)
+ if 0:
+ for a, b in zip(el1, el2):
+ print a != b and "***************" or ""
+ print a
+ print b
+
+ self.assertEquals(el1, el2,
+ "loaded file not equivalent to the saved file")
+
+
+class ClassificationTest(LoadSessionTest):
+
+ """
+ Base class for tests that do some detailed checking of classifications
+ """
+
+ def TestLayers(self, layers, expected):
+ TITLE = 0
+ NUM_GROUPS = 1
+ CLASSES = 2
+ GROUP_TYPE = 0
+ GROUP_DATA = 1
+ GROUP_LABEL = 2
+ GROUP_PROPS = 3
+
+ eq = self.assertEquals
+
+ eq(len(layers), len(expected))
+
+ for layer, data in zip(layers, expected):
+ eq(layer.Title(), data[TITLE])
+
+ clazz = layer.GetClassification()
+ eq(clazz.GetNumGroups(), data[NUM_GROUPS])
+ eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
+
+ i = 0
+ for group in clazz:
+ props = ClassGroupProperties()
+ props.SetLineColor(
+ parse_color(data[CLASSES][i][GROUP_PROPS][0]))
+ props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
+ props.SetFill(
+ parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+ if len(data[CLASSES][i][GROUP_PROPS]) > 3:
+ props.SetSize(data[CLASSES][i][GROUP_PROPS][3])
+
+ if data[CLASSES][i][GROUP_TYPE] == "default":
+ g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "range":
+ g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
+ data[CLASSES][i][GROUP_DATA][1]),
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "single":
+ g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "pattern":
+ g = ClassGroupPattern(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+
+ eq(group, g)
+
+ i += 1
+
+
+
+class TestSingleLayer(LoadSessionTest):
+
+ # Note: The use of & and non-ascii characters is deliberate. We
+ # want to test whether the loading code handles that correctly.
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="Stra\xc3\x9fen & Landmarken">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="\xc3\x9cbersicht">
+ <projection epsg="32627" name="WGS 84 / UTM zone 27N">
+ <parameter value="datum=WGS84"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="proj=utm"/>
+ <parameter value="units=m"/>
+ <parameter value="zone=27"/>
+ </projection>
+ <layer shapestore="D1" visible="true" title="K\xc3\xbcste">
+ <classification>
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(), internal_from_unicode(u"Stra\xdfen & Landmarken"))
+
+ # the session has one map.
+ maps = session.Maps()
+ eq(len(maps), 1)
+
+ # Check the map's attributes
+ map = maps[0]
+ eq(map.Title(), internal_from_unicode(u"\xdcbersicht"))
+ proj = map.GetProjection()
+ eq(proj.GetName(), "WGS 84 / UTM zone 27N")
+ eq(proj.EPSGCode(), "32627")
+ params = proj.GetAllParameters()
+ params.sort()
+ eq(params, ["datum=WGS84", "ellps=WGS84", "proj=utm", "units=m",
+ "zone=27"])
+
+ # the map has a single layer
+ layers = map.Layers()
+ eq(len(layers), 1)
+
+ # Check the layer attributes
+ layer = layers[0]
+ eq(layer.Title(), internal_from_unicode(u"K\xfcste"))
+ self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "political.shp")))
+ eq(layer.GetClassification().GetDefaultFill(), Transparent)
+ eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
+ eq(layer.Visible(), True)
+
+ self.check_format()
+
+ self.session.Destroy()
+ self.session = None
+
+ def test_leak(self):
+ """Test load_session for resource leaks
+
+ The load_session function had a resource leak in that it created
+ cyclic references. The objects would have been eventually
+ collected by the garbage collector but too late. One symptom is
+ that when layers are removed so that the last normal reference
+ owned indirectly by the session to a shape store goes away, the
+ shape store is not actually removed from the session even though
+ the session only keeps weak references because there are still
+ references owned by the cyclic garbage.
+ """
+ session = load_session(self.filename())
+ self.session = session
+
+ # sanity check
+ self.assertEquals(len(session.ShapeStores()), 1)
+
+ # remove the map. The shapestore should go away too
+ session.RemoveMap(session.Maps()[0])
+ self.assertEquals(len(session.ShapeStores()), 0)
+
+
+class TestNonAsciiColumnName(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="Non ASCII column name test">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="TestNonAsciiColumnName.shp"/>
+ <map title="map">
+ <projection name="Some Projection">
+ <parameter value="datum=WGS84"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="proj=utm"/>
+ <parameter value="units=m"/>
+ <parameter value="zone=27"/>
+ </projection>
+ <layer shapestore="D1" visible="true" title="layer">
+ <classification field="Fl\xc3\xa4che" field_type="double">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+
+ # Create a shapefile and a dbffile with a non-ascii column name
+ dbffile = self.temp_file_name("TestNonAsciiColumnName.dbf")
+ shpfile = self.temp_file_name("TestNonAsciiColumnName.shp")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field('Fl\xe4che', dbflib.FTDouble, 10, 5)
+ dbf.write_record(0, (0.0,))
+ dbf.close()
+ shp = shapelib.create(shpfile, shapelib.SHPT_POLYGON)
+ shp.write_object(-1, shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
+ [[(0,0), (10, 10), (10, 0),
+ (0, 0)]]))
+ shp.close()
+
+ try:
+ session = load_session(self.filename())
+ except ValueError, v:
+ # Usually if the field name is not decoded properly the
+ # loading fails because the field type mentioned in the file
+ # is not None as returned from the layer for a non-existing
+ # column name so we check for that and report it as failure.
+ # Other exceptions are errors in the test case.
+ if str(v) == "xml field type differs from database!":
+ self.fail("Cannot load file with non-ascii column names")
+ else:
+ raise
+ self.session = session
+
+ # In case Thuban could load the file anyway (i.e. no ValueError
+ # exception in load_session()), check explicitly whether the
+ # field name was decoded properly. The test will probably lead
+ # to a UnicodeError instead of a test failure so we check that
+ # too
+ layer = session.Maps()[0].Layers()[0]
+ try:
+ self.assertEquals(layer.GetClassificationColumn(), 'Fl\xe4che')
+ except UnicodeError:
+ # FIXME: Obviously this will have to change if Thuban ever
+ # supports unicode properly.
+ self.fail("Column name was not converted to a bytestring")
+
+ # roundtrip check
+ self.check_format()
+
+
+class TestLayerVisibility(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="false" title="My Layer">
+ <classification>
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the visible flag is correctly loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+ maps = session.Maps()
+ eq(len(maps), 1)
+ map = maps[0]
+ layers = map.Layers()
+ eq(len(layers), 1)
+ layer = layers[0]
+
+ eq(layer.Visible(), False)
+
+ self.check_format()
+
+
+class TestSymbolSize(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
+ <fileshapesource filetype="shapefile" id="D813968480" filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="Iceland map">
+ <layer title="cultural_landmark-point" shapestore="D813968480" visible="true">
+ <classification field="CLPTLABEL" field_type="string">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" size="3" fill="#000000"/>
+ </clnull>
+ <clpoint label="" value="RUINS">
+ <cldata stroke="#000000" stroke_width="1" size="6" fill="#ffffff"/>
+ </clpoint>
+ <clpoint label="" value="FARM">
+ <cldata stroke="#000000" stroke_width="1" size="9" fill="#ffff00"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the size attribute for point symbols is correctly
+ loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = session.Maps()[0] # only one map in the sample
+
+ expected = [("cultural_landmark-point", 2,
+ [("default", (), "",
+ ("#000000", 1, "#000000", 3)),
+ ("single", "RUINS", "",
+ ("#000000", 1, "#ffffff", 6)),
+ ("single", "FARM", "",
+ ("#000000", 1, "#ffff00", 9))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+ self.check_format()
+
+
+class TestClassification(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D138389860"
+ filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D138504492"
+ filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D123456789"
+ filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="Test Map">
+ <projection name="">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D138389860" visible="true" title="My Layer">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ <clpoint label="" value="1">
+ <cldata stroke="#000000" stroke_width="10" fill="None"/>
+ </clpoint>
+ <clpoint label="\xc3\x9cml\xc3\xa4uts"
+ value="\xc3\xa4\xc3\xb6\xc3\xbc">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D138504492" visible="true" title="My Layer 2">
+ <classification field="AREA" field_type="double">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clnull>
+ <clrange label="" range="[0;1[">
+ <cldata stroke="#111111" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint label="" value="0.5">
+ <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
+ </clpoint>
+ <clrange label="" range="[-1;0[">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint label="" value="-0.5">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D123456789" visible="true" title="My Layer 3">
+ <classification field="CLPTLABEL" field_type="string">
+ <clnull label="">
+ <cldata stroke="#000000" size="5" stroke_width="2" fill="None"/>
+ </clnull>
+ <clpoint label="" value="FARM">
+ <cldata stroke="#111111" size="5" stroke_width="1" fill="None"/>
+ </clpoint>
+ <clpattern label="" pattern="BUI">
+ <cldata stroke="#000000" size="5" stroke_width="1" fill="None"/>
+ </clpattern>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban session with a map and classified layers."""
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 3,
+ [("default", (), "",
+ ("#000000", 1, "None")),
+ ("single", "1", "",
+ ("#000000", 2, "None")),
+ ("single", "1", "",
+ ("#000000", 10, "None")),
+ ("single", internal_from_unicode(u"\xe4\xf6\xfc"),
+ internal_from_unicode(u"\xdcml\xe4uts"),
+ ("#000000", 1, "None"))]),
+ ("My Layer 2", 4,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("range", (0, 1), "",
+ ("#111111", 1, "None")),
+ ("single", .5, "",
+ ("#000000", 1, "#111111")),
+ ("range", (-1, 0), "",
+ ("#000000", 1, "None")),
+ ("single", -.5, "",
+ ("#000000", 1, "None"))]),
+ ("My Layer 3", 2,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("single", "FARM", "",
+ ("#111111", 1, "None")),
+ ("pattern", "BUI", "",
+ ("#000000", 1, "None"))]),
+ ]
+
+ self.TestLayers(map.Layers(), expected)
+
+ self.check_format()
+
+
+class TestLabels(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true" title="My Layer">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session and test for reading the group labels."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 1,
+ [("default", (), "hallo",
+ ("#000000", 1, "None")),
+ ("single", "1", "welt",
+ ("#000000", 2, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+ self.check_format()
+
+
+class TestLayerProjection(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D2"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <fileshapesource filetype="shapefile" id="D4"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D4" visible="true" title="My Layer">
+ <projection name="hello">
+ <parameter value="zone=13"/>
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D2" visible="true" title="My Layer">
+ <projection name="Unknown">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10"/>
+ <parameter value="lat_2=20"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification>
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading layers with projections"""
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layers = map.Layers() # two layers in the sample
+
+ # test layer with a named projection
+ proj = layers[0].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "hello")
+ eq(proj.GetParameter("proj"), "tmerc")
+ eq(proj.GetParameter("zone"), "13")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+ # test layer with an unnamed projection
+ proj = layers[1].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "Unknown")
+ eq(proj.GetParameter("proj"), "lcc")
+ eq(proj.GetParameter("lat_1"), "10")
+ eq(proj.GetParameter("lat_2"), "20")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+ self.check_format()
+
+
+class TestRasterLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <map title="Test Map">
+ <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
+ title="My RasterLayer" opacity="0.4" masktype="alpha"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layer = map.Layers()[0] # one layer in the sample
+
+ eq(layer.Title(), "My RasterLayer")
+ eq(layer.Opacity(), 0.4)
+ eq(layer.MaskType(), layer.MASK_ALPHA)
+
+ self.failIf(layer.Visible())
+ self.failUnless(filenames_equal(layer.GetImageFilename(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "island.tif")))
+ self.check_format()
+
+
+class TestJoinedTable(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="A Joined Table session">
+ <fileshapesource filetype="shapefile" id="D137227612"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
+ title="Some Title"/>
+ <jointable id="D136169900" title="Joined"
+ right="D136171140" left="D137227612"
+ leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
+ jointype="LEFT OUTER"/>
+ <derivedshapesource table="D136169900" shapesource="D137227612"
+ id="D136170932"/>
+ <map title="Test Map">
+ <layer shapestore="D136170932" visible="true" title="My Layer">
+ <classification>
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend inherited method to create the dbffile for the join"""
+ LoadSessionTest.setUp(self)
+ dbffile = self.temp_file_name("load_joinedtable.dbf")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
+ dbf.add_field("TEXT", dbflib.FTString, 10, 0)
+ dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
+ dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
+ dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
+ dbf.close()
+
+ def test(self):
+ """Test loading a session containing a joined table"""
+ session = load_session(self.filename())
+ self.session = session
+
+ tables = session.Tables()
+ self.assertEquals(len(tables), 3)
+ # FIXME: The tests shouldn't assume a certain order of the tables
+ self.assertEquals(tables[0].Title(), "Some Title")
+ self.assertEquals(tables[1].Title(), "Joined")
+ self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
+ self.check_format()
+
+
+class TestLabelLayer(LoadSessionTest):
+
+ # Note that the labels deliberately contain non-ascii characters to
+ # test whether they're supported correctly.
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="Thuban sample session">
+ <fileshapesource filetype="shapefile" id="D145265052"
+ filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D145412868"
+ filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="Iceland map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D145265052" visible="true" title="political">
+ <projection name="Geographic">
+ <parameter value="proj=latlong"/>
+ <parameter value="to_meter=0.017453"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification>
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="#c0c0c0"/>
+ </clnull>
+ </classification>
+ </layer>
+ <layer shapestore="D145412868" visible="true" title="landmarks">
+ <projection name="Geographic">
+ <parameter value="proj=latlong"/>
+ <parameter value="to_meter=0.017453"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification>
+ <clnull label="">
+ <cldata size="5" stroke="#000000" stroke_width="1" fill="#ffff00"/>
+ </clnull>
+ </classification>
+ </layer>
+ <labellayer>
+ <label x="-21.5" y="64.25" text="RUINS"
+ halign="left" valign="center"/>
+ <label x="-15.125" y="64.75" text="H\xc3\xbctte"
+ halign="right" valign="top"/>
+ </labellayer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session with a label layer"""
+ session = load_session(self.filename())
+ self.session = session
+
+ label_layer = self.session.Maps()[0].LabelLayer()
+ expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
+ (-15.125, 64.75, internal_from_unicode(u"H\xfctte"),
+ ALIGN_RIGHT, ALIGN_TOP),
+ ]
+ for label, values in zip(label_layer.Labels(), expected_labels):
+ self.assertEquals((label.x, label.y, label.text, label.halign,
+ label.valign),
+ values)
+ self.check_format()
+
+
+class TestPostGISLayer(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource id="D143149420" dbconn="D142684948"
+ tablename="landmarks_point_id" id_column="point_id"
+ geometry_column="the_geom" />
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ def test(self):
+ """Test loading a session containing a postgis shapestore"""
+ session = load_session(self.filename())
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+
+
+class TestPostGISLayerPassword(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ self.db_connection_callback_called = False
+ self.server.require_authentication(True)
+
+ def tearDown(self):
+ """Extend the inherited method to switch off postgresql authentication
+ """
+ self.server.require_authentication(False)
+ LoadSessionTest.tearDown(self)
+
+ def db_connection_callback(self, params, message):
+ """Implementation of Thuban.Model.hooks.query_db_connection_parameters
+ """
+ self.assertEquals(params,
+ {"dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": str(self.server.port),
+ "host": self.server.host})
+ self.db_connection_callback_called = True
+ params = params.copy()
+ params["password"] = self.server.user_password
+ return params
+
+ def test_with_callback(self):
+ """Test loading a session with postgis, authentication and a callback
+ """
+ session = load_session(self.filename(),
+ db_connection_callback = self.db_connection_callback)
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+ self.failUnless(self.db_connection_callback_called)
+
+ def test_without_callback(self):
+ """Test loading a session with postgis, authentication and no callback
+ """
+ # A password is required and there's no callback, so we should
+ # get a ConnectionError
+ self.assertRaises(ConnectionError, load_session, self.filename())
+
+ def test_cancel(self):
+ """Test loading a session with postgis and cancelling authentication
+ """
+ def cancel(*args):
+ self.db_connection_callback_called = True
+ return None
+
+ # If the user cancels, i.e. if the callbakc returns None, a
+ # LoadCancelled exception is raised.
+ self.assertRaises(LoadCancelled,
+ load_session, self.filename(), cancel)
+ self.failUnless(self.db_connection_callback_called)
+
+
+class TestLoadError(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ title="single map&layer">
+ <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="My Layer" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session missing a required attribute"""
+ # Don't use assertRaises to make sure that if a session is
+ # actually returned it gets destroyed properly.
+ try:
+ self.session = load_session(self.filename())
+ except LoadError, value:
+ # Check the actual messge in value to make sure the
+ # LoadError really was about the missing attribute
+ self.assertEquals(str(value),
+ "Element "
+ "(u'http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd',"
+ " u'fileshapesource') requires an attribute 'filetype'")
+ else:
+ self.fail("Missing filetype attribute doesn't raise LoadError")
+
+class Shapefile_CallBack:
+
+ def __init__(self, params):
+ """Initialize the callback return values.
+
+ params must be a dictionary of the potential CB modes (keys),
+ with lists of tuples of return values as values.
+ Depending on the test the callback can be called multiple,
+ each time a return value is poped from the list
+ """
+
+ self.params = params
+
+
+ def s_cb(self, filename, mode = None, second_try= 0):
+ if self.params.has_key(mode):
+ return self.params[mode].pop(0)
+ else:
+ raise LoadError
+
+class TestAltPath(LoadSessionTest):
+
+ """Test the various cases in the alternative path feature.
+
+ The test checks the reasonable cases:
+ - First recognition of a path error, fixed with user interaction.
+ - First recognition of a path error, load cancelled.
+ - Path error fixed from list, confirmed by user.
+ - Path error fixed from list, changed by user.
+ - Path error fixed from list, cancelled by user.
+ - Path error wrongly fixed from list, manual fix forced.
+ """
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd" title="AltPath Test session">
+ <fileshapesource filetype="shapefile" id="D1108450956" filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D1108900076" filename="../Data/iceland/roads-line.shp"/>
+ <fileshapesource filetype="shapefile" id="D1108947244" filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="not the iceland map">
+ <layer title="political" stroke_width="1" shapestore="D1108450956" visible="true" stroke="#000000" fill="#c0c0c0"/>
+ <layer title="roads-line" stroke_width="1" shapestore="D1108900076" visible="true" stroke="#000000" fill="None"/>
+ <layer title="something else" stroke_width="1" shapestore="D1108947244" visible="true" stroke="#000000" fill="None"/>
+ </map>
+</session>
+'''
+
+ def checkSession(self, session):
+ """Check if session has been loaded successfully."""
+
+ eq = self.assertEquals
+
+ map = session.Maps()[0]
+ layers = map.Layers()
+
+ eq("AltPath Test session", session.Title())
+ eq("not the iceland map", map.Title())
+ eq(3,len(layers))
+ eq("political",layers[0].Title())
+ eq("roads-line",layers[1].Title())
+ eq("something else",layers[2].Title())
+
+ def test_01_single_path_error_fix(self):
+ """Test single file path error fix."""
+ # The usual initial case
+ s_cb = Shapefile_CallBack({
+ "search": [("../Data/iceland/roads-line.shp",0)],
+ "check": [(None, None)]})
+ self.session = load_session(self.filename(),
+ shapefile_callback =s_cb.s_cb)
+ self.checkSession(self.session)
+
+ def test_02_path_error_fix_from_list(self):
+ """Test single file path error fix."""
+ # This represents the usual case for "from_list"
+ s_cb = Shapefile_CallBack({
+ "search": [("../Data/iceland/roads-line.shp",1)],
+ "check": [(os.path.abspath("../Data/iceland/roads-line.shp"),1)]
+ })
+ self.session = load_session(self.filename(),
+ shapefile_callback =s_cb.s_cb)
+ self.checkSession(self.session)
+
+ def test_03_single_path_error_cancelled(self):
+ """Test alternative path cancelled."""
+ s_cb = Shapefile_CallBack({
+ "search": [(None,0)],
+ "check": [(None, None)]})
+ self.assertRaises(LoadCancelled,
+ load_session, self.filename(), None, s_cb.s_cb)
+
+ def test_04_path_error_fix_from_list_cancelled(self):
+ """Test alternative path from list cancelled."""
+ s_cb = Shapefile_CallBack({
+ "search": [("../Data/iceland/roads-line.shp",1)],
+ "check": [(None,1)]
+ })
+ self.assertRaises(LoadCancelled,
+ load_session, self.filename(), None, s_cb.s_cb)
+
+ def test_05_path_error_fix_from_list_changed(self):
+ """Test alternative path from list changed."""
+ s_cb = Shapefile_CallBack({
+ "search": [("../Data/iceland/roads-line.shp",1)],
+ "check": [("../Data/iceland/roads-line.shp",0)]
+ })
+ self.session = load_session(self.filename(),
+ shapefile_callback =s_cb.s_cb)
+ self.checkSession(self.session)
+
+ def test_06_path_error_fix_from_list_fails(self):
+ """Test alternative path recovery from list."""
+ s_cb = Shapefile_CallBack({
+ "search": [("../wrong/iceland/roads-line.shp",1),
+ ("../Data/iceland/roads-line.shp",0)],
+ "check": [(None,None)]
+ })
+ self.session = load_session(self.filename(),
+ shapefile_callback =s_cb.s_cb)
+ self.assertRaises(IndexError,
+ s_cb.s_cb, None, "search")
+
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_load_0_2.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_load_0_2.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_load_0_2.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,252 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test loading a thuban session from a files generated by Thuban 0.2 and earlier
+"""
+
+__version__ = "$Revision: 1357 $"
+# $Source$
+# $Id: test_load_0_2.py 1357 2003-07-02 09:38:27Z jonathan $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.load import load_session, parse_color
+from Thuban.Model.color import Transparent
+from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
+ ClassGroupSingleton, ClassGroupDefault
+
+
+def filenames_equal(name1, name2):
+ """Return true if the filenames name1 and name2 are equal.
+
+ On systems where it is available, simply use os.path.samefile,
+ otherwise return whether the normalized versions of the filenames
+ according to os.path.normpath are equal.
+ """
+ if hasattr(os.path, "samefile"):
+ return os.path.samefile(name1, name2)
+ return os.path.normpath(name1) == os.path.normpath(name2)
+
+
+
+class LoadSessionTest(support.FileLoadTestCase):
+
+ """Base class for .thuban file loading tests
+
+ Basically the same as the FileLoadTestCase, except that all tests
+ use the '.thuban' extension by default and that setUp and tearDown
+ handle sessions.
+ """
+
+ file_extension = ".thuban"
+
+ def setUp(self):
+ """Create the test files"""
+ support.FileLoadTestCase.setUp(self)
+ self.session = None
+
+ def tearDown(self):
+ if self.session is not None:
+ self.session.Destroy()
+ self.session = None
+
+
+class ClassificationTest(LoadSessionTest):
+
+ """
+ Base class for tests that do some detailed checking of classifications
+ """
+
+ def TestLayers(self, layers, expected):
+ TITLE = 0
+ NUM_GROUPS = 1
+ CLASSES = 2
+ GROUP_TYPE = 0
+ GROUP_DATA = 1
+ GROUP_LABEL = 2
+ GROUP_PROPS = 3
+
+ eq = self.assertEquals
+
+ eq(len(layers), len(expected))
+
+ for layer, data in zip(layers, expected):
+ eq(layer.Title(), data[TITLE])
+
+ clazz = layer.GetClassification()
+ eq(clazz.GetNumGroups(), data[NUM_GROUPS])
+ eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
+
+ i = 0
+ for group in clazz:
+ props = ClassGroupProperties()
+ props.SetLineColor(
+ parse_color(data[CLASSES][i][GROUP_PROPS][0]))
+ props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
+ props.SetFill(
+ parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+
+ if data[CLASSES][i][GROUP_TYPE] == "default":
+ g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "range":
+ g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
+ data[CLASSES][i][GROUP_DATA][1]),
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "single":
+ g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+
+ eq(group, g)
+
+ i += 1
+
+
+
+class TestSingleLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban.dtd">
+<session title="single map&layer">
+ <map title="Test Map">
+ <projection>
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban 0.2 session with a single map with a single layer"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(), "single map&layer")
+
+ # the session has one map.
+ maps = session.Maps()
+ eq(len(maps), 1)
+
+ # Check the map's attributes
+ map = maps[0]
+ eq(map.Title(), "Test Map")
+
+ # the map has a single layer
+ layers = map.Layers()
+ eq(len(layers), 1)
+
+ # Check the layer attributes
+ layer = layers[0]
+ eq(layer.Title(), "My Layer")
+ self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "political.shp")))
+ eq(layer.GetClassification().GetDefaultFill(), Transparent)
+ eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
+ eq(layer.Visible(), True)
+
+ self.session.Destroy()
+ self.session = None
+
+
+class TestClassification(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban.dtd">
+<session title="single map&layer">
+ <map title="Test Map">
+ <projection>
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="POPYREG" field_type="string">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="10" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer title="My Layer 2" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="AREA" field_type="double">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clnull>
+ <clrange min="0" max="1">
+ <cldata stroke="#111111" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value=".5">
+ <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
+ </clpoint>
+ <clrange min="-1" max="0">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value="-.5">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban 0.2 session with a map and classified layers."""
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 2,
+ [("default", (), "",
+ ("#000000", 1, "None")),
+ ("single", "1", "",
+ ("#000000", 2, "None")),
+ ("single", "1", "",
+ ("#000000", 10, "None"))]),
+ ("My Layer 2", 4,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("range", (0, 1), "",
+ ("#111111", 1, "None")),
+ ("single", .5, "",
+ ("#000000", 1, "#111111")),
+ ("range", (-1, 0), "",
+ ("#000000", 1, "None")),
+ ("single", -.5, "",
+ ("#000000", 1, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_load_0_8.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_load_0_8.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_load_0_8.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,592 @@
+# Copyright (c) 2002, 2003, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test loading a thuban session from a file generated by Thuban 0.8.0 or 0.8.1
+"""
+
+__version__ = "$Revision: 2642 $"
+# $Source$
+# $Id: test_load_0_8.py 2642 2005-07-01 20:49:04Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import dbflib
+
+from Thuban import internal_from_unicode
+from Thuban.Model.load import load_session, parse_color, LoadError
+from Thuban.Model.color import Transparent
+from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
+ ClassGroupSingleton, ClassGroupDefault
+
+
+def filenames_equal(name1, name2):
+ """Return true if the filenames name1 and name2 are equal.
+
+ On systems where it is available, simply use os.path.samefile,
+ otherwise return whether the normalized versions of the filenames
+ according to os.path.normpath are equal.
+ """
+ if hasattr(os.path, "samefile"):
+ return os.path.samefile(name1, name2)
+ return os.path.normpath(name1) == os.path.normpath(name2)
+
+
+
+class LoadSessionTest(support.FileLoadTestCase):
+
+ """Base class for .thuban file loading tests
+
+ Basically the same as the FileLoadTestCase, except that all tests
+ use the '.thuban' extension by default and that setUp and tearDown
+ handle sessions.
+ """
+
+ file_extension = ".thuban"
+
+ def setUp(self):
+ """Create the test files"""
+ support.FileLoadTestCase.setUp(self)
+ self.session = None
+
+ def tearDown(self):
+ if self.session is not None:
+ self.session.Destroy()
+ self.session = None
+
+
+ dtd = "http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ thubanids = [((dtd, n), (None, "id")) for n in
+ ["fileshapesource", "filetable", "jointable",
+ "derivedshapesource"]]
+ thubanidrefs = [((dtd, n), (None, m)) for n, m in
+ [("layer", "shapestore"),
+ ("jointable", "left"),
+ ("jointable", "right"),
+ ("derivedshapesource", "table"),
+ ("derivedshapesource", "shapesource")]]
+ del n, m, dtd
+
+
+class ClassificationTest(LoadSessionTest):
+
+ """
+ Base class for tests that do some detailed checking of classifications
+ """
+
+ def TestLayers(self, layers, expected):
+ TITLE = 0
+ NUM_GROUPS = 1
+ CLASSES = 2
+ GROUP_TYPE = 0
+ GROUP_DATA = 1
+ GROUP_LABEL = 2
+ GROUP_PROPS = 3
+
+ eq = self.assertEquals
+
+ eq(len(layers), len(expected))
+
+ for layer, data in zip(layers, expected):
+ eq(layer.Title(), data[TITLE])
+
+ clazz = layer.GetClassification()
+ eq(clazz.GetNumGroups(), data[NUM_GROUPS])
+ eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
+
+ i = 0
+ for group in clazz:
+ props = ClassGroupProperties()
+ props.SetLineColor(
+ parse_color(data[CLASSES][i][GROUP_PROPS][0]))
+ props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
+ props.SetFill(
+ parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+
+ if data[CLASSES][i][GROUP_TYPE] == "default":
+ g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "range":
+ g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
+ data[CLASSES][i][GROUP_DATA][1]),
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "single":
+ g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+
+ eq(group, g)
+
+ i += 1
+
+
+
+class TestSingleLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="My Layer" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(), "single map&layer")
+
+ # the session has one map.
+ maps = session.Maps()
+ eq(len(maps), 1)
+
+ # Check the map's attributes
+ map = maps[0]
+ eq(map.Title(), "Test Map")
+
+ # the map has a single layer
+ layers = map.Layers()
+ eq(len(layers), 1)
+
+ # Check the layer attributes
+ layer = layers[0]
+ eq(layer.Title(), "My Layer")
+ self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "political.shp")))
+ eq(layer.GetClassification().GetDefaultFill(), Transparent)
+ eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
+ eq(layer.Visible(), True)
+
+ self.session.Destroy()
+ self.session = None
+
+
+class TestLayerVisibility(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="false" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the visible flag is correctly loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+ maps = session.Maps()
+ eq(len(maps), 1)
+ map = maps[0]
+ layers = map.Layers()
+ eq(len(layers), 1)
+ layer = layers[0]
+
+ eq(layer.Visible(), False)
+
+
+class TestClassification(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban.dtd">
+<session title="single map&layer">
+ <map title="Test Map">
+ <projection>
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="POPYREG" field_type="string">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="10" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer title="My Layer 2" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="AREA" field_type="double">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clnull>
+ <clrange min="0" max="1">
+ <cldata stroke="#111111" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value=".5">
+ <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
+ </clpoint>
+ <clrange min="-1" max="0">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value="-.5">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban session with a map and classified layers."""
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 2,
+ [("default", (), "",
+ ("#000000", 1, "None")),
+ ("single", "1", "",
+ ("#000000", 2, "None")),
+ ("single", "1", "",
+ ("#000000", 10, "None"))]),
+ ("My Layer 2", 4,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("range", (0, 1), "",
+ ("#111111", 1, "None")),
+ ("single", .5, "",
+ ("#000000", 1, "#111111")),
+ ("range", (-1, 0), "",
+ ("#000000", 1, "None")),
+ ("single", -.5, "",
+ ("#000000", 1, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+class TestLabels(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session and test for reading the group labels."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 1,
+ [("default", (), "hallo",
+ ("#000000", 1, "None")),
+ ("single", "1", "welt",
+ ("#000000", 2, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+class TestLayerProjection(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D2"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <fileshapesource filetype="shapefile" id="D4"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D4" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="hello">
+ <parameter value="zone=13"/>
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D2" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="Unknown">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10"/>
+ <parameter value="lat_2=20"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading layers with projections"""
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layers = map.Layers() # two layers in the sample
+
+ # test layer with a named projection
+ proj = layers[0].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "hello")
+ eq(proj.GetParameter("proj"), "tmerc")
+ eq(proj.GetParameter("zone"), "13")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+ # test layer with an unnamed projection
+ proj = layers[1].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "Unknown")
+ eq(proj.GetParameter("proj"), "lcc")
+ eq(proj.GetParameter("lat_1"), "10")
+ eq(proj.GetParameter("lat_2"), "20")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+
+class TestRasterLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <map title="Test Map">
+ <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
+ title="My RasterLayer"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layer = map.Layers()[0] # one layer in the sample
+
+ eq(layer.Title(), "My RasterLayer")
+ self.failIf(layer.Visible())
+ self.failUnless(filenames_equal(layer.GetImageFilename(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "island.tif")))
+
+class TestJoinedTable(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd" title="A Joined Table session">
+ <fileshapesource filetype="shapefile" id="D137227612"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
+ title="Some Title"/>
+ <jointable leftcolumn="RDLNTYPE" right="D136171140"
+ title="Joined" rightcolumn="RDTYPE" id="D136169900" left="D137227612"/>
+ <derivedshapesource table="D136169900" shapesource="D137227612"
+ id="D136170932"/>
+ <map title="Test Map">
+ <layer shapestore="D136170932" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend inherited method to create the dbffile for the join"""
+ LoadSessionTest.setUp(self)
+ dbffile = self.temp_file_name("load_joinedtable.dbf")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
+ dbf.add_field("TEXT", dbflib.FTString, 10, 0)
+ dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
+ dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
+ dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
+ dbf.close()
+
+ def test(self):
+ """Test loading a session containing a joined table"""
+ session = load_session(self.filename())
+ self.session = session
+
+ tables = session.Tables()
+ self.assertEquals(len(tables), 3)
+ # FIXME: The tests shouldn't assume a certain order of the tables
+ self.assertEquals(tables[0].Title(), "Some Title")
+ self.assertEquals(tables[1].Title(), "Joined")
+ self.assertEquals(tables[1].JoinType(), "INNER")
+
+
+class TestLoadError(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="single map&layer">
+ <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="My Layer" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session missing a required attribute"""
+ # Don't use assertRaises to make sure that if a session is
+ # actually returned it gets destroyed properly.
+ try:
+ self.session = load_session(self.filename())
+ except LoadError, value:
+ pass
+ else:
+ self.fail("Missing filetype attribute doesn't raise LoadError")
+
+
+class TestUnicodeStrings(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.8.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.8.dtd"
+ title="Frida: Free Vector Geodata Osnabr\xc3\xbcck">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Osnabr\xc3\xbcck">
+ <projection name="Osnabr\xc3\xbcck Projection">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="Osnabr\xc3\xbcck Layer"
+ stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with unicode strings"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(),
+ internal_from_unicode(u"Frida: Free Vector Geodata Osnabr\xfcck"))
+
+ # Check the map's title
+ maps = session.Maps()
+ map = maps[0]
+ eq(map.Title(), internal_from_unicode(u"Osnabr\xfcck"))
+
+ # Check the layer's title
+ layers = map.Layers()
+ layer = layers[0]
+ eq(layer.Title(), internal_from_unicode(u"Osnabr\xfcck Layer"))
+
+ # Check the projection's title
+ projection = map.GetProjection()
+ eq(projection.GetName(),
+ internal_from_unicode(u"Osnabr\xfcck Projection"))
+
+ self.session.Destroy()
+ self.session = None
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_load_0_9.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_load_0_9.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_load_0_9.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,714 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test loading a thuban session from a file written by Thuban 0.9.
+
+See test_load.py for how the various test_load*.py files relate to each other.
+"""
+
+__version__ = "$Revision: 2642 $"
+# $Source$
+# $Id: test_load_0_9.py 2642 2005-07-01 20:49:04Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import postgissupport
+from xmlsupport import sax_eventlist
+
+import dbflib
+
+from Thuban import internal_from_unicode
+from Thuban.Model.save import save_session
+from Thuban.Model.load import load_session, parse_color, LoadError, \
+ LoadCancelled
+from Thuban.Model.color import Transparent
+from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
+ ClassGroupSingleton, ClassGroupDefault
+from Thuban.Model.postgisdb import ConnectionError
+
+def filenames_equal(name1, name2):
+ """Return true if the filenames name1 and name2 are equal.
+
+ On systems where it is available, simply use os.path.samefile,
+ otherwise return whether the normalized versions of the filenames
+ according to os.path.normpath are equal.
+ """
+ if hasattr(os.path, "samefile"):
+ return os.path.samefile(name1, name2)
+ return os.path.normpath(name1) == os.path.normpath(name2)
+
+
+
+class LoadSessionTest(support.FileLoadTestCase):
+
+ """Base class for .thuban file loading tests
+
+ Basically the same as the FileLoadTestCase, except that all tests
+ use the '.thuban' extension by default and that setUp and tearDown
+ handle sessions.
+ """
+
+ file_extension = ".thuban"
+
+ def setUp(self):
+ """Create the test files"""
+ support.FileLoadTestCase.setUp(self)
+ self.session = None
+
+ def tearDown(self):
+ if self.session is not None:
+ self.session.Destroy()
+ self.session = None
+
+
+ dtd = "http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ thubanids = [((dtd, n), (None, "id")) for n in
+ ["fileshapesource", "filetable", "jointable",
+ "derivedshapesource"]]
+ thubanidrefs = [((dtd, n), (None, m)) for n, m in
+ [("layer", "shapestore"),
+ ("jointable", "left"),
+ ("jointable", "right"),
+ ("derivedshapesource", "table"),
+ ("derivedshapesource", "shapesource")]]
+ filenames = [((dtd, n), (None, m)) for n, m in
+ [("fileshapesource", "filename"),
+ ("rasterlayer", "filename"),
+ ("filetable", "filename")]]
+ del n, m, dtd
+
+
+
+class ClassificationTest(LoadSessionTest):
+
+ """
+ Base class for tests that do some detailed checking of classifications
+ """
+
+ def TestLayers(self, layers, expected):
+ TITLE = 0
+ NUM_GROUPS = 1
+ CLASSES = 2
+ GROUP_TYPE = 0
+ GROUP_DATA = 1
+ GROUP_LABEL = 2
+ GROUP_PROPS = 3
+
+ eq = self.assertEquals
+
+ eq(len(layers), len(expected))
+
+ for layer, data in zip(layers, expected):
+ eq(layer.Title(), data[TITLE])
+
+ clazz = layer.GetClassification()
+ eq(clazz.GetNumGroups(), data[NUM_GROUPS])
+ eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
+
+ i = 0
+ for group in clazz:
+ props = ClassGroupProperties()
+ props.SetLineColor(
+ parse_color(data[CLASSES][i][GROUP_PROPS][0]))
+ props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
+ props.SetFill(
+ parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+
+ if data[CLASSES][i][GROUP_TYPE] == "default":
+ g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "range":
+ g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
+ data[CLASSES][i][GROUP_DATA][1]),
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "single":
+ g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+
+ eq(group, g)
+
+ i += 1
+
+
+
+class TestSingleLayer(LoadSessionTest):
+
+ # Note: The use of & and non-ascii characters is deliberate. We
+ # want to test whether the loading code handles that correctly.
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="Stra\xc3\x9fen & Landmarken">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="\xc3\x9cbersicht">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(), internal_from_unicode(u"Stra\xdfen & Landmarken"))
+
+ # the session has one map.
+ maps = session.Maps()
+ eq(len(maps), 1)
+
+ # Check the map's attributes
+ map = maps[0]
+ eq(map.Title(), internal_from_unicode(u"\xdcbersicht"))
+
+ # the map has a single layer
+ layers = map.Layers()
+ eq(len(layers), 1)
+
+ # Check the layer attributes
+ layer = layers[0]
+ eq(layer.Title(), internal_from_unicode(u"K\xfcste"))
+ self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "political.shp")))
+ eq(layer.GetClassification().GetDefaultFill(), Transparent)
+ eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
+ eq(layer.Visible(), True)
+
+ self.session.Destroy()
+ self.session = None
+
+
+class TestLayerVisibility(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="false" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the visible flag is correctly loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+ maps = session.Maps()
+ eq(len(maps), 1)
+ map = maps[0]
+ layers = map.Layers()
+ eq(len(layers), 1)
+ layer = layers[0]
+
+ eq(layer.Visible(), False)
+
+
+class TestClassification(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban.dtd">
+<session title="single map&layer">
+ <map title="Test Map">
+ <projection>
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="POPYREG" field_type="string">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ <clpoint value="1">
+ <cldata stroke="#000000" stroke_width="10" fill="None"/>
+ </clpoint>
+ <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
+ label="\xc3\x9cml\xc3\xa4uts">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer title="My Layer 2" stroke_width="1" fill="None"
+ filename="../../Data/iceland/political.shp"
+ stroke="#000000">
+ <classification field="AREA" field_type="double">
+ <clnull>
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clnull>
+ <clrange min="0" max="1">
+ <cldata stroke="#111111" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value=".5">
+ <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
+ </clpoint>
+ <clrange min="-1" max="0">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint value="-.5">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban session with a map and classified layers."""
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 3,
+ [("default", (), "",
+ ("#000000", 1, "None")),
+ ("single", "1", "",
+ ("#000000", 2, "None")),
+ ("single", "1", "",
+ ("#000000", 10, "None")),
+ ("single", internal_from_unicode(u"\xe4\xf6\xfc"),
+ internal_from_unicode(u"\xdcml\xe4uts"),
+ ("#000000", 1, "None"))]),
+ ("My Layer 2", 4,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("range", (0, 1), "",
+ ("#111111", 1, "None")),
+ ("single", .5, "",
+ ("#000000", 1, "#111111")),
+ ("range", (-1, 0), "",
+ ("#000000", 1, "None")),
+ ("single", -.5, "",
+ ("#000000", 1, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+class TestLabels(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session and test for reading the group labels."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 1,
+ [("default", (), "hallo",
+ ("#000000", 1, "None")),
+ ("single", "1", "welt",
+ ("#000000", 2, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+class TestLayerProjection(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D2"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <fileshapesource filetype="shapefile" id="D4"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D4" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="hello">
+ <parameter value="zone=13"/>
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D2" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="Unknown">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10"/>
+ <parameter value="lat_2=20"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading layers with projections"""
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layers = map.Layers() # two layers in the sample
+
+ # test layer with a named projection
+ proj = layers[0].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "hello")
+ eq(proj.GetParameter("proj"), "tmerc")
+ eq(proj.GetParameter("zone"), "13")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+ # test layer with an unnamed projection
+ proj = layers[1].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "Unknown")
+ eq(proj.GetParameter("proj"), "lcc")
+ eq(proj.GetParameter("lat_1"), "10")
+ eq(proj.GetParameter("lat_2"), "20")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+
+
+class TestRasterLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="single map&layer">
+ <map title="Test Map">
+ <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
+ title="My RasterLayer"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layer = map.Layers()[0] # one layer in the sample
+
+ eq(layer.Title(), "My RasterLayer")
+ self.failIf(layer.Visible())
+ self.failUnless(filenames_equal(layer.GetImageFilename(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "island.tif")))
+
+
+class TestJoinedTable(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd" title="A Joined Table session">
+ <fileshapesource filetype="shapefile" id="D137227612"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
+ title="Some Title"/>
+ <jointable id="D136169900" title="Joined"
+ right="D136171140" left="D137227612"
+ leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
+ jointype="LEFT OUTER"/>
+ <derivedshapesource table="D136169900" shapesource="D137227612"
+ id="D136170932"/>
+ <map title="Test Map">
+ <layer shapestore="D136170932" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend inherited method to create the dbffile for the join"""
+ LoadSessionTest.setUp(self)
+ dbffile = self.temp_file_name("load_joinedtable.dbf")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
+ dbf.add_field("TEXT", dbflib.FTString, 10, 0)
+ dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
+ dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
+ dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
+ dbf.close()
+
+ def test(self):
+ """Test loading a session containing a joined table"""
+ session = load_session(self.filename())
+ self.session = session
+
+ tables = session.Tables()
+ self.assertEquals(len(tables), 3)
+ # FIXME: The tests shouldn't assume a certain order of the tables
+ self.assertEquals(tables[0].Title(), "Some Title")
+ self.assertEquals(tables[1].Title(), "Joined")
+ self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
+
+
+
+class TestPostGISLayer(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ def test(self):
+ """Test loading a session containing a postgis shapestore"""
+ session = load_session(self.filename())
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+
+
+class TestPostGISLayerPassword(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ self.db_connection_callback_called = False
+ self.server.require_authentication(True)
+
+ def tearDown(self):
+ """Extend the inherited method to switch off postgresql authentication
+ """
+ self.server.require_authentication(False)
+ LoadSessionTest.tearDown(self)
+
+ def db_connection_callback(self, params, message):
+ """Implementation of Thuban.Model.hooks.query_db_connection_parameters
+ """
+ self.assertEquals(params,
+ {"dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": str(self.server.port),
+ "host": self.server.host})
+ self.db_connection_callback_called = True
+ params = params.copy()
+ params["password"] = self.server.user_password
+ return params
+
+ def test_with_callback(self):
+ """Test loading a session with postgis, authentication and a callback
+ """
+ session = load_session(self.filename(),
+ db_connection_callback = self.db_connection_callback)
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+ self.failUnless(self.db_connection_callback_called)
+
+ def test_without_callback(self):
+ """Test loading a session with postgis, authentication and no callback
+ """
+ # A password is required and there's no callback, so we should
+ # get a ConnectionError
+ self.assertRaises(ConnectionError, load_session, self.filename())
+
+ def test_cancel(self):
+ """Test loading a session with postgis and cancelling authentication
+ """
+ def cancel(*args):
+ self.db_connection_callback_called = True
+ return None
+
+ # If the user cancels, i.e. if the callbakc returns None, a
+ # LoadCancelled exception is raised.
+ self.assertRaises(LoadCancelled,
+ load_session, self.filename(), cancel)
+ self.failUnless(self.db_connection_callback_called)
+
+
+class TestLoadError(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-0.9.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd"
+ title="single map&layer">
+ <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="My Layer" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session missing a required attribute"""
+ # Don't use assertRaises to make sure that if a session is
+ # actually returned it gets destroyed properly.
+ try:
+ self.session = load_session(self.filename())
+ except LoadError, value:
+ # Check the actual messge in value to make sure the
+ # LoadError really was about the missing attribute
+ self.assertEquals(str(value),
+ "Element "
+ "(u'http://thuban.intevation.org/dtds/thuban-0.9.dtd',"
+ " u'fileshapesource') requires an attribute 'filetype'")
+ else:
+ self.fail("Missing filetype attribute doesn't raise LoadError")
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_load_1_0.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_load_1_0.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_load_1_0.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,884 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test loading a thuban session from a file written by Thuban 1.0 or an 1.0aX
+
+See test_load.py for how the various test_load*.py files relate to each other.
+"""
+
+__version__ = "$Revision: 2642 $"
+# $Source$
+# $Id: test_load_1_0.py 2642 2005-07-01 20:49:04Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import postgissupport
+from xmlsupport import sax_eventlist
+
+import dbflib
+import shapelib
+
+from Thuban import internal_from_unicode
+from Thuban.Model.save import save_session
+from Thuban.Model.load import load_session, parse_color, LoadError, \
+ LoadCancelled
+from Thuban.Model.color import Transparent
+from Thuban.Model.classification import ClassGroupProperties, ClassGroupRange,\
+ ClassGroupSingleton, ClassGroupDefault
+from Thuban.Model.postgisdb import ConnectionError
+from Thuban.Model.table import DBFTable, MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING, \
+ table_to_dbf
+from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
+ ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
+
+
+def filenames_equal(name1, name2):
+ """Return true if the filenames name1 and name2 are equal.
+
+ On systems where it is available, simply use os.path.samefile,
+ otherwise return whether the normalized versions of the filenames
+ according to os.path.normpath are equal.
+ """
+ if hasattr(os.path, "samefile"):
+ return os.path.samefile(name1, name2)
+ return os.path.normpath(name1) == os.path.normpath(name2)
+
+
+
+class LoadSessionTest(support.FileLoadTestCase):
+
+ """Base class for .thuban file loading tests
+
+ Basically the same as the FileLoadTestCase, except that all tests
+ use the '.thuban' extension by default and that setUp and tearDown
+ handle sessions.
+ """
+
+ file_extension = ".thuban"
+
+ def setUp(self):
+ """Create the test files"""
+ support.FileLoadTestCase.setUp(self)
+ self.session = None
+
+ def tearDown(self):
+ if self.session is not None:
+ self.session.Destroy()
+ self.session = None
+
+
+ dtd = "http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ thubanids = [((dtd, n), (None, "id")) for n in
+ ["fileshapesource", "filetable", "jointable",
+ "derivedshapesource"]]
+ thubanidrefs = [((dtd, n), (None, m)) for n, m in
+ [("layer", "shapestore"),
+ ("jointable", "left"),
+ ("jointable", "right"),
+ ("derivedshapesource", "table"),
+ ("derivedshapesource", "shapesource")]]
+
+ # The filenames in the tests should be understandable on all
+ # currently supported platforms so filenames is an empty list
+ filenames = []
+
+ del n, m, dtd
+
+
+
+class ClassificationTest(LoadSessionTest):
+
+ """
+ Base class for tests that do some detailed checking of classifications
+ """
+
+ def TestLayers(self, layers, expected):
+ TITLE = 0
+ NUM_GROUPS = 1
+ CLASSES = 2
+ GROUP_TYPE = 0
+ GROUP_DATA = 1
+ GROUP_LABEL = 2
+ GROUP_PROPS = 3
+
+ eq = self.assertEquals
+
+ eq(len(layers), len(expected))
+
+ for layer, data in zip(layers, expected):
+ eq(layer.Title(), data[TITLE])
+
+ clazz = layer.GetClassification()
+ eq(clazz.GetNumGroups(), data[NUM_GROUPS])
+ eq(clazz.GetNumGroups() + 1, len(data[CLASSES]))
+
+ i = 0
+ for group in clazz:
+ props = ClassGroupProperties()
+ props.SetLineColor(
+ parse_color(data[CLASSES][i][GROUP_PROPS][0]))
+ props.SetLineWidth(data[CLASSES][i][GROUP_PROPS][1])
+ props.SetFill(
+ parse_color(data[CLASSES][i][GROUP_PROPS][2]))
+
+ if data[CLASSES][i][GROUP_TYPE] == "default":
+ g = ClassGroupDefault(props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "range":
+ g = ClassGroupRange((data[CLASSES][i][GROUP_DATA][0],
+ data[CLASSES][i][GROUP_DATA][1]),
+ props, data[CLASSES][i][GROUP_LABEL])
+ elif data[CLASSES][i][GROUP_TYPE] == "single":
+ g = ClassGroupSingleton(data[CLASSES][i][GROUP_DATA],
+ props, data[CLASSES][i][GROUP_LABEL])
+
+ eq(group, g)
+
+ i += 1
+
+
+
+class TestSingleLayer(LoadSessionTest):
+
+ # Note: The use of & and non-ascii characters is deliberate. We
+ # want to test whether the loading code handles that correctly.
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="Stra\xc3\x9fen & Landmarken">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="\xc3\x9cbersicht">
+ <projection epsg="32627" name="WGS 84 / UTM zone 27N">
+ <parameter value="datum=WGS84"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="proj=utm"/>
+ <parameter value="units=m"/>
+ <parameter value="zone=27"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="K\xc3\xbcste" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ # Check the title
+ eq(session.Title(), internal_from_unicode(u"Stra\xdfen & Landmarken"))
+
+ # the session has one map.
+ maps = session.Maps()
+ eq(len(maps), 1)
+
+ # Check the map's attributes
+ map = maps[0]
+ eq(map.Title(), internal_from_unicode(u"\xdcbersicht"))
+ proj = map.GetProjection()
+ eq(proj.GetName(), "WGS 84 / UTM zone 27N")
+ eq(proj.EPSGCode(), "32627")
+ params = proj.GetAllParameters()
+ params.sort()
+ eq(params, ["datum=WGS84", "ellps=WGS84", "proj=utm", "units=m",
+ "zone=27"])
+
+ # the map has a single layer
+ layers = map.Layers()
+ eq(len(layers), 1)
+
+ # Check the layer attributes
+ layer = layers[0]
+ eq(layer.Title(), internal_from_unicode(u"K\xfcste"))
+ self.failUnless(filenames_equal(layer.ShapeStore().FileName(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "political.shp")))
+ eq(layer.GetClassification().GetDefaultFill(), Transparent)
+ eq(layer.GetClassification().GetDefaultLineColor().hex(), "#000000")
+ eq(layer.Visible(), True)
+
+ self.session.Destroy()
+ self.session = None
+
+ def test_leak(self):
+ """Test load_session for resource leaks
+
+ The load_session function had a resource leak in that it created
+ cyclic references. The objects would have been eventually
+ collected by the garbage collector but too late. One symptom is
+ that when layers are removed so that the last normal reference
+ owned indirectly by the session to a shape store goes away, the
+ shape store is not actually removed from the session even though
+ the session only keeps weak references because there are still
+ references owned by the cyclic garbage.
+ """
+ session = load_session(self.filename())
+ self.session = session
+
+ # sanity check
+ self.assertEquals(len(session.ShapeStores()), 1)
+
+ # remove the map. The shapestore should go away too
+ session.RemoveMap(session.Maps()[0])
+ self.assertEquals(len(session.ShapeStores()), 0)
+
+
+class TestNonAsciiColumnName(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="Non ASCII column name test">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="TestNonAsciiColumnName.shp"/>
+ <map title="map">
+ <projection name="Some Projection">
+ <parameter value="datum=WGS84"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="proj=utm"/>
+ <parameter value="units=m"/>
+ <parameter value="zone=27"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="layer" stroke_width="1"
+ fill="None">
+ <classification field="Fl\xc3\xa4che" field_type="double">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session with a single map with a single layer"""
+
+ # Create a shapefile and a dbffile with a non-ascii column name
+ dbffile = self.temp_file_name("TestNonAsciiColumnName.dbf")
+ shpfile = self.temp_file_name("TestNonAsciiColumnName.shp")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field('Fl\xe4che', dbflib.FTDouble, 10, 5)
+ dbf.write_record(0, (0.0,))
+ dbf.close()
+ shp = shapelib.create(shpfile, shapelib.SHPT_POLYGON)
+ shp.write_object(-1, shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
+ [[(0,0), (10, 10), (10, 0),
+ (0, 0)]]))
+ shp.close()
+
+ try:
+ session = load_session(self.filename())
+ except ValueError, v:
+ # Usually if the field name is not decoded properly the
+ # loading fails because the field type mentioned in the file
+ # is not None as returned from the layer for a non-existing
+ # column name so we check for that and report it as failure.
+ # Other exceptions are errors in the test case.
+ if str(v) == "xml field type differs from database!":
+ self.fail("Cannot load file with non-ascii column names")
+ else:
+ raise
+ self.session = session
+
+ # In case Thuban could load the file anyway (i.e. no ValueError
+ # exception in load_session()), check explicitly whether the
+ # field name was decoded properly. The test will probably lead
+ # to a UnicodeError instead of a test failure so we check that
+ # too
+ layer = session.Maps()[0].Layers()[0]
+ try:
+ self.assertEquals(layer.GetClassificationColumn(), 'Fl\xe4che')
+ except UnicodeError:
+ # FIXME: Obviously this will have to change if Thuban ever
+ # supports unicode properly.
+ self.fail("Column name was not converted to a bytestring")
+
+
+class TestLayerVisibility(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="false" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test that the visible flag is correctly loaded for a layer."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+ maps = session.Maps()
+ eq(len(maps), 1)
+ map = maps[0]
+ layers = map.Layers()
+ eq(len(layers), 1)
+ layer = layers[0]
+
+ eq(layer.Visible(), False)
+
+
+class TestClassification(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D138389860"
+ filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D138504492"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D138389860" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ <clpoint label="" value="1">
+ <cldata stroke="#000000" stroke_width="10" fill="None"/>
+ </clpoint>
+ <clpoint label="\xc3\x9cml\xc3\xa4uts"
+ value="\xc3\xa4\xc3\xb6\xc3\xbc">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D138504492" visible="true" stroke="#000000"
+ title="My Layer 2" stroke_width="2" fill="None">
+ <classification field="AREA" field_type="double">
+ <clnull label="">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clnull>
+ <clrange label="" range="[0;1[">
+ <cldata stroke="#111111" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint label="" value="0.5">
+ <cldata stroke="#000000" stroke_width="1" fill="#111111"/>
+ </clpoint>
+ <clrange label="" range="[-1;0[">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clrange>
+ <clpoint label="" value="-0.5">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a Thuban session with a map and classified layers."""
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 3,
+ [("default", (), "",
+ ("#000000", 1, "None")),
+ ("single", "1", "",
+ ("#000000", 2, "None")),
+ ("single", "1", "",
+ ("#000000", 10, "None")),
+ ("single", internal_from_unicode(u"\xe4\xf6\xfc"),
+ internal_from_unicode(u"\xdcml\xe4uts"),
+ ("#000000", 1, "None"))]),
+ ("My Layer 2", 4,
+ [("default", (), "",
+ ("#000000", 2, "None")),
+ ("range", (0, 1), "",
+ ("#111111", 1, "None")),
+ ("single", .5, "",
+ ("#000000", 1, "#111111")),
+ ("range", (-1, 0), "",
+ ("#000000", 1, "None")),
+ ("single", -.5, "",
+ ("#000000", 1, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+
+class TestLabels(ClassificationTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D1"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Load a session and test for reading the group labels."""
+ eq = self.assertEquals
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ expected = [("My Layer", 1,
+ [("default", (), "hallo",
+ ("#000000", 1, "None")),
+ ("single", "1", "welt",
+ ("#000000", 2, "None"))])]
+
+ self.TestLayers(map.Layers(), expected)
+
+class TestLayerProjection(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <fileshapesource filetype="shapefile" id="D2"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <fileshapesource filetype="shapefile" id="D4"
+ filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D4" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="hello">
+ <parameter value="zone=13"/>
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <classification field="POPYREG" field_type="string">
+ <clnull label="hallo">
+ <cldata stroke="#000000" stroke_width="1" fill="None"/>
+ </clnull>
+ <clpoint label="welt" value="1">
+ <cldata stroke="#000000" stroke_width="2" fill="None"/>
+ </clpoint>
+ </classification>
+ </layer>
+ <layer shapestore="D2" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None">
+ <projection name="Unknown">
+ <parameter value="proj=lcc"/>
+ <parameter value="lat_1=10"/>
+ <parameter value="lat_2=20"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ </layer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading layers with projections"""
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layers = map.Layers() # two layers in the sample
+
+ # test layer with a named projection
+ proj = layers[0].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "hello")
+ eq(proj.GetParameter("proj"), "tmerc")
+ eq(proj.GetParameter("zone"), "13")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+ # test layer with an unnamed projection
+ proj = layers[1].GetProjection()
+ neq(proj, None)
+ eq(proj.GetName(), "Unknown")
+ eq(proj.GetParameter("proj"), "lcc")
+ eq(proj.GetParameter("lat_1"), "10")
+ eq(proj.GetParameter("lat_2"), "20")
+ eq(proj.GetParameter("ellps"), "clrk66")
+
+
+class TestRasterLayer(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <map title="Test Map">
+ <rasterlayer visible="false" filename="../../Data/iceland/island.tif"
+ title="My RasterLayer"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ eq = self.assertEquals
+ neq = self.assertNotEqual
+
+ session = load_session(self.filename())
+ self.session = session
+
+ map = self.session.Maps()[0] # only one map in the sample
+
+ layer = map.Layers()[0] # one layer in the sample
+
+ eq(layer.Title(), "My RasterLayer")
+ self.failIf(layer.Visible())
+ self.failUnless(filenames_equal(layer.GetImageFilename(),
+ os.path.join(self.temp_dir(),
+ os.pardir, os.pardir,
+ "Data", "iceland",
+ "island.tif")))
+
+class TestJoinedTable(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd" title="A Joined Table session">
+ <fileshapesource filetype="shapefile" id="D137227612"
+ filename="../../Data/iceland/roads-line.shp"/>
+ <filetable filetype="DBF" filename="load_joinedtable.dbf" id="D136171140"
+ title="Some Title"/>
+ <jointable id="D136169900" title="Joined"
+ right="D136171140" left="D137227612"
+ leftcolumn="RDLNTYPE" rightcolumn="RDTYPE"
+ jointype="LEFT OUTER"/>
+ <derivedshapesource table="D136169900" shapesource="D137227612"
+ id="D136170932"/>
+ <map title="Test Map">
+ <layer shapestore="D136170932" visible="true" stroke="#000000"
+ title="My Layer" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend inherited method to create the dbffile for the join"""
+ LoadSessionTest.setUp(self)
+ dbffile = self.temp_file_name("load_joinedtable.dbf")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
+ dbf.add_field("TEXT", dbflib.FTString, 10, 0)
+ dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
+ dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
+ dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
+ dbf.close()
+
+ def test(self):
+ """Test loading a session containing a joined table"""
+ session = load_session(self.filename())
+ self.session = session
+
+ tables = session.Tables()
+ self.assertEquals(len(tables), 3)
+ # FIXME: The tests shouldn't assume a certain order of the tables
+ self.assertEquals(tables[0].Title(), "Some Title")
+ self.assertEquals(tables[1].Title(), "Joined")
+ self.assertEquals(tables[1].JoinType(), "LEFT OUTER")
+
+class TestLabelLayer(LoadSessionTest):
+
+ # Note that the labels deliberately contain non-ascii characters to
+ # test whether they're supported correctly.
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd" title="Thuban sample session">
+ <fileshapesource filetype="shapefile" id="D145265052"
+ filename="../../Data/iceland/political.shp"/>
+ <fileshapesource filetype="shapefile" id="D145412868"
+ filename="../../Data/iceland/cultural_landmark-point.shp"/>
+ <map title="Iceland map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D145265052" visible="true" stroke="#000000"
+ title="political" stroke_width="1" fill="#c0c0c0">
+ <projection name="Geographic">
+ <parameter value="proj=latlong"/>
+ <parameter value="to_meter=0.017453"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ </layer>
+ <layer shapestore="D145412868" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="#ffff00">
+ <projection name="Geographic">
+ <parameter value="proj=latlong"/>
+ <parameter value="to_meter=0.017453"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ </layer>
+ <labellayer>
+ <label x="-21.5" y="64.25" text="RUINS"
+ halign="left" valign="center"/>
+ <label x="-15.125" y="64.75" text="H\xc3\xbctte"
+ halign="right" valign="top"/>
+ </labellayer>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session with a label layer"""
+ session = load_session(self.filename())
+ self.session = session
+
+ label_layer = self.session.Maps()[0].LabelLayer()
+ expected_labels = [(-21.5, 64.25, "RUINS", ALIGN_LEFT, ALIGN_CENTER),
+ (-15.125, 64.75, internal_from_unicode(u"H\xfctte"),
+ ALIGN_RIGHT, ALIGN_TOP),
+ ]
+ for label, values in zip(label_layer.Labels(), expected_labels):
+ self.assertEquals((label.x, label.y, label.text, label.halign,
+ label.valign),
+ values)
+
+class TestPostGISLayer(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ def test(self):
+ """Test loading a session containing a postgis shapestore"""
+ session = load_session(self.filename())
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+
+
+class TestPostGISLayerPassword(LoadSessionTest):
+
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="unnamed session">
+ <dbconnection port="%(port)s" host="%(host)s" user="%(user)s"
+ dbtype="postgis" id="D142684948" dbname="%(dbname)s"/>
+ <dbshapesource tablename="landmarks" id="D143149420" dbconn="D142684948"/>
+ <map title="unnamed map">
+ <layer shapestore="D143149420" visible="true" stroke="#000000"
+ title="landmarks" stroke_width="1" fill="None"/>
+ </map>
+</session>
+'''
+
+ def setUp(self):
+ """Extend the inherited method to start the postgis server
+
+ Furthermore, patch the file contents with the real postgis db
+ information
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+
+ self.file_contents = self.__class__.file_contents % {
+ "dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": self.server.port,
+ "host": self.server.host}
+ LoadSessionTest.setUp(self)
+
+ self.db_connection_callback_called = False
+ self.server.require_authentication(True)
+
+ def tearDown(self):
+ """Extend the inherited method to switch off postgresql authentication
+ """
+ self.server.require_authentication(False)
+ LoadSessionTest.tearDown(self)
+
+ def db_connection_callback(self, params, message):
+ """Implementation of Thuban.Model.hooks.query_db_connection_parameters
+ """
+ self.assertEquals(params,
+ {"dbname": self.postgisdb.dbname,
+ "user": self.server.user_name,
+ "port": str(self.server.port),
+ "host": self.server.host})
+ self.db_connection_callback_called = True
+ params = params.copy()
+ params["password"] = self.server.user_password
+ return params
+
+ def test_with_callback(self):
+ """Test loading a session with postgis, authentication and a callback
+ """
+ session = load_session(self.filename(),
+ db_connection_callback = self.db_connection_callback)
+ self.session = session
+ connections = session.DBConnections()
+ self.assertEquals(len(connections), 1)
+ conn = connections[0]
+ for attr, value in [("host", self.server.host),
+ ("port", str(self.server.port)),
+ ("user", self.server.user_name),
+ ("dbname", self.postgisdb.dbname)]:
+ self.assertEquals(getattr(conn, attr), value)
+ layer = session.Maps()[0].Layers()[0]
+ self.failUnless(layer.ShapeStore().DBConnection() is conn)
+ self.failUnless(self.db_connection_callback_called)
+
+ def test_without_callback(self):
+ """Test loading a session with postgis, authentication and no callback
+ """
+ # A password is required and there's no callback, so we should
+ # get a ConnectionError
+ self.assertRaises(ConnectionError, load_session, self.filename())
+
+ def test_cancel(self):
+ """Test loading a session with postgis and cancelling authentication
+ """
+ def cancel(*args):
+ self.db_connection_callback_called = True
+ return None
+
+ # If the user cancels, i.e. if the callbakc returns None, a
+ # LoadCancelled exception is raised.
+ self.assertRaises(LoadCancelled,
+ load_session, self.filename(), cancel)
+ self.failUnless(self.db_connection_callback_called)
+
+
+class TestLoadError(LoadSessionTest):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE session SYSTEM "thuban-1.0.dtd">
+<session xmlns="http://thuban.intevation.org/dtds/thuban-1.0.0.dtd"
+ title="single map&layer">
+ <fileshapesource id="D1" filename="../../Data/iceland/political.shp"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer shapestore="D1" visible="true"
+ stroke="#000000" title="My Layer" stroke_width="1"
+ fill="None"/>
+ </map>
+</session>
+'''
+
+ def test(self):
+ """Test loading a session missing a required attribute"""
+ # Don't use assertRaises to make sure that if a session is
+ # actually returned it gets destroyed properly.
+ try:
+ self.session = load_session(self.filename())
+ except LoadError, value:
+ # Check the actual messge in value to make sure the
+ # LoadError really was about the missing attribute
+ self.assertEquals(str(value),
+ "Element "
+ "(u'http://thuban.intevation.org/dtds/thuban-1.0.0.dtd',"
+ " u'fileshapesource') requires an attribute 'filetype'")
+ else:
+ self.fail("Missing filetype attribute doesn't raise LoadError")
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_map.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_map.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_map.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,308 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Map class
+"""
+
+__version__ = "$Revision: 2575 $"
+# $Source$
+# $Id: test_map.py 2575 2005-02-22 11:09:32Z jan $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.messages import CHANGED, MAP_PROJECTION_CHANGED, \
+ MAP_LAYERS_CHANGED, MAP_LAYERS_ADDED, MAP_LAYERS_REMOVED,\
+ MAP_STACKING_CHANGED, LAYER_VISIBILITY_CHANGED, LAYER_LEGEND_CHANGED, \
+ LAYER_CHANGED
+
+from Thuban.Model.session import Session
+from Thuban.Model.map import Map
+from Thuban.Model.layer import Layer
+from Thuban.Model.proj import Projection
+from Thuban.Model.color import Color
+
+
+class TestMapSimple(unittest.TestCase):
+
+ """Very simple test cases for Map"""
+
+ def test_initial_state(self):
+ """Test Map's initial state"""
+ map = Map("Test Map")
+ self.assertEquals(map.Title(), "Test Map")
+ self.assertEquals(map.Layers(), [])
+ label_layer = map.LabelLayer()
+ self.assertEquals(label_layer.Title(), "Labels")
+ self.assertEquals(label_layer.Labels(), [])
+ self.failIf(map.WasModified())
+ map.Destroy()
+
+ def test_empty_map(self):
+ """Test empty Map"""
+ map = Map("Test Map")
+ self.assertEquals(map.BoundingBox(), None)
+ self.assertEquals(map.ProjectedBoundingBox(), None)
+ self.failIf(map.HasLayers())
+ map.Destroy()
+
+
+class TestMapBase(unittest.TestCase, support.SubscriberMixin):
+
+ """Base class for Map test cases that test messages"""
+
+ def setUp(self):
+ """
+ Clear the message list, create self.map and subscribe to its messages
+ """
+ self.clear_messages()
+
+ # Create a Map and subscribe to all interesting channels.
+ self.map = Map("Test Map")
+ for channel in (CHANGED,
+ MAP_PROJECTION_CHANGED,
+ MAP_LAYERS_CHANGED,
+ MAP_LAYERS_ADDED,
+ MAP_LAYERS_REMOVED,
+ MAP_STACKING_CHANGED,
+ LAYER_VISIBILITY_CHANGED,
+ LAYER_LEGEND_CHANGED,
+ LAYER_CHANGED):
+ self.map.Subscribe(channel, self.subscribe_with_params, channel)
+
+ def tearDown(self):
+ """Destroy self.map and self.session and clear the message list"""
+ if hasattr(self, "session"):
+ self.session.Destroy()
+ self.session = None
+ self.map.Destroy()
+ self.map = None
+ self.clear_messages()
+
+
+class TestMapAddLayer(TestMapBase):
+
+ """Simple test cases involving messages"""
+
+ def test_add_layer(self):
+ """Test Map.AddLayer"""
+ # make sure the created Map is unmodified
+ session = self.session = Session("Test session for %s" %self.__class__)
+ self.failIf(self.map.WasModified())
+ self.failIf(self.map.HasLayers())
+
+ # add a layer and check the result
+ filename = os.path.join("..", "Data", "iceland", "roads-line.shp")
+ roads = Layer("Roads", session.OpenShapefile(filename))
+ self.map.AddLayer(roads)
+ self.assertEquals(self.map.Layers(), [roads])
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_LAYERS_ADDED)])
+ self.assert_(self.map.WasModified())
+ self.assert_(self.map.HasLayers())
+
+
+class TestMapWithContents(TestMapBase, support.FloatComparisonMixin):
+
+ """More complex Map test cases with messages that.
+
+ All test cases here start with a non-empty map.
+ """
+
+ def setUp(self):
+ """Extend the inherited method to also fill the Map.
+
+ Put some layers into the map created by the inherited method and
+ reset its modified flag. Make also sure that the list of
+ received messages is empty.
+ """
+ TestMapBase.setUp(self)
+ self.session = Session("Test session for %s" % self.__class__)
+ open_shp = self.session.OpenShapefile
+ self.arc_layer = Layer("Roads",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "roads-line.shp")))
+ self.poly_layer = Layer("Political",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "political.shp")))
+ self.map.AddLayer(self.arc_layer)
+ self.map.AddLayer(self.poly_layer)
+ self.map.UnsetModified()
+ self.clear_messages()
+
+ def tearDown(self):
+ TestMapBase.tearDown(self)
+ self.session = None
+ self.map = None
+ self.poly_layer = self.arc_layer = None
+
+ def test_remove_layer(self):
+ """Test Map.RemoveLayer"""
+ self.map.RemoveLayer(self.arc_layer)
+ self.assert_(self.map.WasModified())
+ self.assertEquals(self.map.Layers(), [self.poly_layer])
+ self.map.UnsetModified()
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_LAYERS_REMOVED),
+ (CHANGED,)])
+
+ def test_clear_layers(self):
+ """Test Map.ClearLayers"""
+ self.map.ClearLayers()
+ self.assertEquals(self.map.Layers(), [])
+ self.assertEquals(self.map.LabelLayer().Labels(), [])
+ self.check_messages([(MAP_LAYERS_CHANGED,),
+ (self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_LAYERS_REMOVED)])
+ self.assert_(self.map.WasModified())
+ self.failIf(self.map.HasLayers())
+
+ def test_raise_layer(self):
+ """Test Map.RaiseLayer"""
+ self.map.RaiseLayer(self.arc_layer)
+ self.assertEquals(self.map.Layers(), [self.poly_layer, self.arc_layer])
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_STACKING_CHANGED)])
+ self.assert_(self.map.WasModified())
+
+ def test_raise_layer_top(self):
+ """Test Map.MoveLayerToTop"""
+ open_shp = self.session.OpenShapefile
+ dummy = Layer("Roads",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "roads-line.shp")))
+ self.map.AddLayer(dummy)
+ self.clear_messages()
+
+ self.map.MoveLayerToTop(self.poly_layer)
+ self.assertEquals(self.map.Layers(),
+ [self.arc_layer, dummy, self.poly_layer])
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_STACKING_CHANGED)])
+ self.assert_(self.map.WasModified())
+
+ self.map.RemoveLayer(dummy)
+
+ def test_lower_layer_bottom(self):
+ """Test Map.MoveLayerToBottom"""
+ open_shp = self.session.OpenShapefile
+ dummy = Layer("Roads",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "roads-line.shp")))
+ self.map.AddLayer(dummy)
+ self.clear_messages()
+
+ self.map.MoveLayerToBottom(dummy)
+ self.assertEquals(self.map.Layers(),
+ [dummy, self.arc_layer, self.poly_layer])
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_STACKING_CHANGED)])
+ self.assert_(self.map.WasModified())
+
+ self.map.RemoveLayer(dummy)
+
+ def test_raise_highest_layer(self):
+ """Test Map.RaiseLayer with highest layer
+
+ Attempting to raise the highest layer should not modify the map.
+ In particular it should not send any messages.
+ """
+ self.map.RaiseLayer(self.poly_layer)
+ self.assertEquals(self.map.Layers(), [self.arc_layer, self.poly_layer])
+ self.check_messages([])
+ self.failIf(self.map.WasModified())
+
+ def test_lower_layer(self):
+ """Test Map.LowerLayer"""
+ self.map.LowerLayer(self.poly_layer)
+ self.assertEquals(self.map.Layers(), [self.poly_layer, self.arc_layer])
+ self.check_messages([(self.map, MAP_LAYERS_CHANGED),
+ (self.map, MAP_STACKING_CHANGED)])
+ self.assert_(self.map.WasModified())
+
+ def test_lower_lowest_layer(self):
+ """Test Map.LowerLayer with lowest layer.
+
+ Attempting to lower the lowest layer should not modify the map.
+ In particular it should not send any messages.
+ """
+ self.map.LowerLayer(self.arc_layer)
+ self.assertEquals(self.map.Layers(), [self.arc_layer, self.poly_layer])
+ self.check_messages([])
+ self.failIf(self.map.WasModified())
+
+ def test_bounding_box(self):
+ """Test Map.BoundingBox"""
+ self.assertFloatSeqEqual(self.map.BoundingBox(),
+ (-24.546524047851562, 63.286754608154297,
+ -13.495815277099609, 66.563774108886719))
+
+ def test_projected_bounding_box(self):
+ """Test Map.ProjectedBoundingBox"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ self.assertFloatSeqEqual(self.map.ProjectedBoundingBox(),
+ (608873.03380603762, 7019694.6517963577,
+ 1173560.0288053728, 7447353.2203218574),
+ epsilon = 1e-5)
+
+ def test_set_projection(self):
+ """Test Map.SetProjection"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ self.check_messages([(self.map, None, MAP_PROJECTION_CHANGED)])
+ self.assert_(self.map.WasModified())
+
+ def test_tree_info(self):
+ """Test Map.TreeInfo"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ # compute the extent string because there are platform
+ # differences in the way %g is handled:
+ # glibc: "%g" % 7.01969e+06 == "7.01969e+06"
+ # w32/VC: "%g" % 7.01969e+06 == "7.01969e+006"
+ extent = 'Extent (projected): (%g, %g, %g, %g)'\
+ % (608873, 7.01969e+06, 1.17356e+06, 7.44735e+06)
+ self.assertEquals(self.map.TreeInfo(),
+ ('Map: Test Map',
+ [('Extent (lat-lon):'
+ ' (-24.5465, 63.2868, -13.4958, 66.5638)'),
+ extent,
+ ('Projection',
+ ['zone=26', 'proj=utm', 'ellps=clrk66']),
+ self.poly_layer,
+ self.arc_layer,
+ self.map.LabelLayer()]))
+
+ def test_forwarding_visibility(self):
+ """Test Map's forwarding of Layer.SetVisible messages"""
+ self.poly_layer.SetVisible(0)
+ self.check_messages([(self.poly_layer, LAYER_VISIBILITY_CHANGED)])
+
+ def test_unset_modified(self):
+ """Test Map.UnsetModified.
+
+ Test whether a change to a layer results in the map being
+ considered modified and test whether then calling the map's
+ UnsetModified clears the changed flag in the layer as well.
+ """
+ self.failIf(self.map.WasModified())
+ self.poly_layer.GetClassification().SetDefaultFill(Color(0.0, 0.5, 1.0))
+ self.assert_(self.map.WasModified())
+ self.map.UnsetModified()
+ self.failIf(self.map.WasModified())
+ self.failIf(self.poly_layer.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_CHANGED),
+ (CHANGED,)])
+
+if __name__ == "__main__":
+ support.run_tests()
+
Added: packages/thuban/branches/upstream/current/test/test_memory_table.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_memory_table.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_memory_table.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,147 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the MemoryTable class
+"""
+
+__version__ = "$Revision: 1662 $"
+# $Source$
+# $Id: test_memory_table.py 1662 2003-08-27 13:51:01Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.table import MemoryTable, \
+ FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
+import dbflib
+
+
+
+class TestMemoryTable(unittest.TestCase):
+
+ def setUp(self):
+ """Create a new dbf file. The name is in self.filename"""
+ self.table = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 0.25, 100),
+ ("bar", 1e10, 17)])
+
+ def test_num_rows(self):
+ """Test MemoryTable.NumRows()"""
+ self.assertEquals(self.table.NumRows(), 4)
+
+ def test_num_columns(self):
+ """Test MemoryTable.NumColumns()"""
+ self.assertEquals(self.table.NumColumns(), 3)
+
+ def test_columns(self):
+ """Test MemoryTable.Columns()"""
+ columns = self.table.Columns()
+ self.assertEquals(columns[0].name, "type")
+ self.assertEquals(columns[0].type, FIELDTYPE_STRING)
+ self.assertEquals(columns[1].name, "value")
+ self.assertEquals(columns[1].type, FIELDTYPE_DOUBLE)
+ self.assertEquals(columns[2].name, "code")
+ self.assertEquals(columns[2].type, FIELDTYPE_INT)
+
+ def test_column(self):
+ """Test MemoryTable.Column()"""
+ # The Column method can be called with either an index or a name
+ col = self.table.Column(2)
+ self.assertEquals(col.name, "code")
+ self.assertEquals(col.type, FIELDTYPE_INT)
+ col = self.table.Column("value")
+ self.assertEquals(col.name, "value")
+ self.assertEquals(col.type, FIELDTYPE_DOUBLE)
+
+ def test_has_column(self):
+ """Test MemoryTable.HasColumn()"""
+ # HasColumn
+ self.failUnless(self.table.HasColumn("value"))
+ self.failUnless(self.table.HasColumn(2))
+ # HasColumn for non-exisiting columns
+ self.failIf(self.table.HasColumn("non_existing_name"))
+ self.failIf(self.table.HasColumn(100))
+
+ def test_read_row_as_dict(self):
+ """Test MemoryTable.ReadRowAsDict()"""
+ self.assertEquals(self.table.ReadRowAsDict(1),
+ {"type": "Foo", "value": 0.5, "code": -1})
+
+ def test_read_row_as_dict_row_count_mode(self):
+ """Test MemoryTable.ReadRowAsDict() row count address mode"""
+ self.assertEquals(self.table.ReadRowAsDict(1, row_is_ordinal = 1),
+ {"type": "Foo", "value": 0.5, "code": -1})
+
+ def test_read_value(self):
+ """Test MemoryTable.ReadValue()"""
+ # The column in ReadValue may be given as either name or index
+ self.assertEquals(self.table.ReadValue(2, 0), "Foo")
+ self.assertEquals(self.table.ReadValue(3, "code"), 17)
+
+ def test_read_value_row_count_mode(self):
+ """Test MemoryTable.ReadValue() row count address mode"""
+ # The column in ReadValue may be given as either name or index
+ self.assertEquals(self.table.ReadValue(2, 0, row_is_ordinal = 1),
+ "Foo")
+ self.assertEquals(self.table.ReadValue(3, "code", row_is_ordinal=1),
+ 17)
+
+ def test_row_id_to_ordinal(self):
+ """Test MemoryTable.RowIdToOrdinal()"""
+ self.assertEquals(self.table.RowIdToOrdinal(5), 5)
+
+ def test_row_oridnal_to_id(self):
+ """Test MemoryTable.RowOrdinalToId()"""
+ self.assertEquals(self.table.RowOrdinalToId(5), 5)
+
+ def test_value_range(self):
+ """Test MemoryTable.ValueRange()"""
+ self.assertEquals(self.table.ValueRange("code"), (-1, 100))
+ self.assertEquals(self.table.ValueRange(1), (0, 1e10))
+
+ def test_unique_values(self):
+ """Test MemoryTable.UniqueValues()"""
+ # The column can be specified by name or index
+ self.assertEquals(self.table.UniqueValues("type"),
+ ["Foo", "UNKNOWN", "bar"])
+ self.assertEquals(self.table.UniqueValues(2), [-1, 0, 17, 100])
+
+ def test_write(self):
+ """Test MemoryTable.write_record()"""
+ # change only one field
+ # TODO: acticate when implemented
+ # table.write_record(2, {"type": "FARMS"})
+
+ # check whether the table returns the new value
+ # TODO: acticate when implemented
+ #eq(table.read_record(2),
+ # {'type': "FARMS", "height": 400.44, "code": 2})
+
+ # Check whether we can specify the record as a tuple
+ self.table.write_record(3, ("HUTS", 111.11, 42))
+ self.assertEquals(self.table.ReadRowAsDict(3),
+ {"type": "HUTS", "value": 111.11, "code": 42})
+
+ def test_dependencies(self):
+ """Test MemoryTable.Dependencies()"""
+ # A MemoryTable doesn't have dependencies
+ self.assertEquals(len(self.table.Dependencies()), 0)
+
+ def test_title(self):
+ """Test MemoryTable.Title()"""
+ self.assertEquals(self.table.Title(), "MemoryTable")
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_menu.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_menu.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_menu.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,122 @@
+# Copyright (c) 2002 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Menu
+"""
+
+__version__ = "$Revision: 2205 $"
+# $Source$
+# $Id: test_menu.py 2205 2004-05-12 20:50:33Z jan $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.UI.menu import Menu
+
+
+class MenuTest(unittest.TestCase):
+
+ def compare_menus(self, menu1, menu2):
+ eq = self.assertEquals
+ ass = self.assert_
+ ass(isinstance(menu1, Menu))
+ ass(isinstance(menu2, Menu))
+ eq(menu1.name, menu2.name)
+ self.compare_items(menu1.items, menu2.items)
+
+ def compare_items(self, items1, items2):
+ eq = self.assertEquals
+ eq(len(items1), len(items2), "Item lists have different lengths")
+ for i in range(len(items1)):
+ i1 = items1[i]
+ i2 = items2[i]
+ if isinstance(i1, Menu):
+ self.compare_menus(i1, i2)
+ else:
+ eq(i1, i2)
+
+ def test(self):
+ """Menu operations (adding new items and submenus)"""
+ eq = self.assertEquals
+
+ # Build a typical main menu for an application. Here we have
+ # only the file menu as sub-menu at first.
+ # Make sure we copy the file_items list so that it won't be
+ # modified
+ file_items = ["new", None, "open", "save"]
+ menu = Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:])])
+
+ # fetch the file submenu
+ filemenu = menu.find_menu("file")
+ # check whether it's the right one
+ self.compare_menus(filemenu, Menu("file", "File", file_items[:]))
+
+ # append a separator and an item to the file menu
+ filemenu.InsertSeparator()
+ filemenu.InsertItem("exit")
+ file_items.extend([None, "exit"])
+ self.compare_menus(filemenu, Menu("file", "File", file_items[:]))
+
+ # append an item to the file menu
+ filemenu.InsertItem("save_as", after="save")
+ file_items.insert(4, "save_as")
+ self.compare_menus(filemenu, Menu("file", "File", file_items[:]))
+
+ # add a new sub-menu to the main menu
+ help_items = ["about", "manual"]
+ helpmenu = menu.InsertMenu("help", "Help")
+ helpmenu.SetItems(help_items[:])
+
+ self.compare_menus(menu, Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:]),
+ Menu("help", "Help", help_items[:])]))
+
+ self.compare_menus(helpmenu, Menu("help", "Help", help_items[:]))
+
+ # add new sub-menu after the file menu but before the help menu
+ edit_items = ["cut", "copy", "paste"]
+ editmenu = menu.InsertMenu("edit", "Edit", after="file")
+ editmenu.SetItems(edit_items[:])
+
+ self.compare_menus(editmenu, Menu("edit", "Edit", edit_items[:]))
+ self.compare_menus(menu, Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:]),
+ Menu("edit", "Edit", edit_items[:]),
+ Menu("help", "Help", help_items[:])]))
+
+ # remove an item from the menu
+ self.compare_menus(editmenu, Menu("edit", "Edit", edit_items[:]))
+ editmenu.RemoveItem("copy")
+ self.compare_menus(editmenu, Menu("edit", "Edit", ['cut', 'paste']))
+ editmenu.InsertItem("copy", after="cut") # for convenience for
+ # the following tests
+
+ # find-or-insert a menu
+ self.compare_menus(menu, Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:]),
+ Menu("edit", "Edit", edit_items[:]),
+ Menu("help", "Help", help_items[:])]))
+ menu.FindOrInsertMenu("extensions", "Extensions")
+ self.compare_menus(menu, Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:]),
+ Menu("edit", "Edit", edit_items[:]),
+ Menu("help", "Help", help_items[:]),
+ Menu("extensions", "Extensions", [])]))
+ menu.FindOrInsertMenu("extensions", "Extensions")
+ self.compare_menus(menu, Menu("<main>", "<main>",
+ [Menu("file", "File", file_items[:]),
+ Menu("edit", "Edit", edit_items[:]),
+ Menu("help", "Help", help_items[:]),
+ Menu("extensions", "Extensions", [])]))
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_mockgeo.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_mockgeo.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_mockgeo.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,47 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test cases for the mockgeo helper objects"""
+
+__version__ = "$Revision: 1585 $"
+# $Source$
+# $Id: test_mockgeo.py 1585 2003-08-15 10:26:40Z bh $
+
+import unittest
+
+import mockgeo
+
+import support
+
+class TestAffineProjection(unittest.TestCase, support.FloatComparisonMixin):
+
+ def test_forward(self):
+ """Test AffineProjection.Forward()"""
+ proj = mockgeo.AffineProjection((0.25, 0.1, 2, 0.125, 100.75, 123.25))
+ self.assertEquals(proj.Forward(0, 0), (100.75, 123.25))
+ self.assertEquals(proj.Forward(10.0, 20.0), (143.25, 126.75))
+ self.assertEquals(proj.Forward(30, 0.125), (108.5, 126.265625))
+
+ def test_inverse(self):
+ """Test AffineProjection.Inverse()"""
+ proj = mockgeo.AffineProjection((0.25, 0.1, 2, 0.125, 100.75, 123.25))
+ self.assertEquals(proj.Inverse(100.75, 123.25), (0, 0))
+ self.assertEquals(proj.Inverse(143.25, 126.75), (10.0, 20.0))
+ self.assertFloatSeqEqual(proj.Inverse(108.5, 126.265625), (30, 0.125))
+
+ def test_int_coeff(self):
+ """Test AffineProjection with integer coefficients"""
+ proj = mockgeo.AffineProjection((1, 1, -1, 1, 0, 0))
+ # The determinant is an int too but must be treated as a float
+ # when dividing by it otherwise some coefficients in the inverse
+ # become wrong.
+ self.assertEquals(proj.Inverse(10, 10), (10, 0))
+
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_postgis_db.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_postgis_db.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_postgis_db.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,931 @@
+# Copyright (C) 2003, 2004, 2005, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test for Thuban.Model.postgisdb"""
+
+import os
+import unittest
+
+
+try:
+ import psycopg
+except ImportError:
+ # No psycopg available. Nothing to be done here because the
+ # postgis.py support module determines this too and the tests will
+ # be skipped completely.
+ pass
+
+import postgissupport
+
+import support
+support.initthuban()
+
+from Thuban.Model.postgisdb import ConnectionError, PostGISConnection, \
+ PostGISTable, PostGISShapeStore
+from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_STRING, \
+ FIELDTYPE_DOUBLE
+from Thuban.Model.data import SHAPETYPE_POINT, SHAPETYPE_POLYGON, \
+ SHAPETYPE_ARC, RAW_WKT
+
+
+class NonConnection(PostGISConnection):
+
+ """Special connection class that doesn't actually connect"""
+
+ def connect(self):
+ pass
+
+
+
+class TestPostGISSimple(unittest.TestCase):
+
+ """Some simple PostGISConnection tests that don't need a real connection"""
+
+ def test_brief_description(self):
+ """Test PostGISConnection.BriefDescription()"""
+ self.assertEquals(NonConnection("somedb").BriefDescription(),
+ "postgis://@:/somedb")
+ self.assertEquals(NonConnection("db", host="here",
+ port="123").BriefDescription(),
+ "postgis://@here:123/db")
+ self.assertEquals(NonConnection("db", user="me",
+ port="123").BriefDescription(),
+ "postgis://me@:123/db")
+
+ def test_matches_parameters(self):
+ """Test PostGISConnection.MatchesParameters()"""
+ def do_test(testfn, conn, host = "", port="", dbname = "", user = ""):
+ testfn(conn.MatchesParameters({"host": host, "port": port,
+ "dbname": dbname, "user": user}))
+
+ do_test(self.assert_, NonConnection("somedb"),
+ dbname="somedb")
+ do_test(self.assert_, NonConnection("somedb", host="here"),
+ dbname="somedb", host="here")
+ do_test(self.assert_, NonConnection("db", user="me", port="123"),
+ dbname="db", port="123", user="me")
+
+ do_test(self.failIf, NonConnection("somedb"),
+ dbname="someotherdb")
+ do_test(self.failIf, NonConnection("somedb", host="here"),
+ dbname="somedb", host="here", port="765")
+ do_test(self.failIf, NonConnection("db", user="me", port="123"),
+ dbname="db", port="123", user="you")
+
+
+class TestPostGISConnection(unittest.TestCase):
+
+ def setUp(self):
+ """Start the server and create a database.
+
+ The database name will be stored in self.dbname, the server
+ object in self.server and the db object in self.db.
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.dbname = ".".join(self.id().split(".")[-2:])[-31:]
+ self.db = self.server.new_postgis_db(self.dbname)
+
+ def test_gis_tables_empty(self):
+ """Test PostGISConnection.GISTables() on empty DB"""
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+
+ # An empty database doesn't have any GIS tables
+ self.assertEquals(db.GeometryTables(), [])
+
+ def test_gis_tables_with_views_and_tables(self):
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+
+ conn = psycopg.connect("dbname=%s " % self.dbname
+ + self.server.connection_string("admin"))
+ cursor = conn.cursor()
+ # First a normal table, i.e. one without a geometry column
+ # we need an explicit WITH OIDS for postgresql >= 8.0
+ cursor.execute("CREATE TABLE normal (A INT, B VARCHAR) WITH OIDS;"
+ "GRANT SELECT ON normal TO PUBLIC;")
+
+ # Then a table with a geometry column
+ # we need an explicit WITH OIDS for postgresql >= 8.0
+ cursor.execute("CREATE TABLE geo (A INT) WITH OIDS;"
+ "GRANT SELECT ON geo TO PUBLIC;")
+ cursor.execute("SELECT AddGeometryColumn(%(dbname)s, 'geo',"
+ " 'the_geom', -1, 'POINT', 2);",
+ {"dbname": self.dbname})
+
+ # And create a view containing a geometry column
+ cursor.execute("CREATE VIEW my_view AS"
+ " (SELECT * FROM geo WHERE a > 100);"
+ "GRANT SELECT ON my_view TO PUBLIC;")
+ conn.commit()
+
+ self.assertEquals(db.GeometryTables(), ["geo", "my_view"])
+ self.assertEquals(db.table_columns("geo"),
+ [("oid", FIELDTYPE_INT), ("a", FIELDTYPE_INT),
+ ("the_geom", "geometry")])
+ self.assertEquals(db.table_columns("my_view"),
+ [("a", FIELDTYPE_INT), ("the_geom", "geometry")])
+ self.assertEquals(db.table_columns("normal"),
+ [("oid", FIELDTYPE_INT), ("a", FIELDTYPE_INT),
+ ("b", FIELDTYPE_STRING)])
+
+
+class TestPostgisDBExceptions(unittest.TestCase):
+
+ def setUp(self):
+ """Start the postgis server and switch on authentication"""
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+ self.server.require_authentication(True)
+
+ def tearDown(self):
+ """Extend the inherited method to switch off postgresql authentication
+ """
+ self.server.require_authentication(False)
+
+ def test_no_password(self):
+ """Test PostGISConnection with omitted but required password"""
+ connection_params = self.server.connection_params("user")
+ # remove the password deliberately
+ del connection_params["password"]
+
+ self.assertRaises(ConnectionError,
+ PostGISConnection, dbname = self.postgisdb.dbname,
+ **connection_params)
+
+
+class TestPostGISSpecialCases(unittest.TestCase):
+
+ """Tests for special cases of PostGIS table usage"""
+
+ def setUp(self):
+ """Start the server and create a database.
+
+ The database name will be stored in self.dbname, the server
+ object in self.server and the db object in self.db.
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.dbname = ".".join(self.id().split(".")[-2:])[-31:]
+ self.db = self.server.new_postgis_db(self.dbname)
+
+ def test_unsupported_types(self):
+ """test PostGISTable on a table with unsupported data types"""
+ stmt = """CREATE TABLE foo (
+ gid integer,
+ ignored bigint,
+ length float);
+ GRANT SELECT ON foo TO PUBLIC;
+ """
+ self.server.execute_sql(self.dbname, "admin", stmt)
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ table = PostGISTable(db, "foo")
+
+ # The bigint column will be ignored because it's not mapped to a
+ # known integer type, so there are only two colunns
+ self.assertEquals(table.NumColumns(), 2)
+ self.assertEquals(table.Column(0).name, "gid")
+ self.assertEquals(table.Column(1).name, "length")
+
+ def test_table_name_quoting(self):
+ """Test whether PostGISTable quotes table names properly"""
+ stmt = '''CREATE TABLE "name with ""quotes"" and spaces" (gid integer);
+ GRANT SELECT ON "name with ""quotes"" and spaces" TO PUBLIC;'''
+ self.server.execute_sql(self.dbname, "admin", stmt)
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ table = PostGISTable(db, 'name with "quotes" and spaces')
+
+ self.assertEquals(table.NumColumns(), 1)
+ self.assertEquals(table.Column(0).name, "gid")
+
+ def test_column_name_quoting(self):
+ """Test whether PostGISTable quotes column names properly"""
+ stmt = '''CREATE TABLE unusual_column_names (
+ gid integer,
+ "with space" float,
+ "with "" quote" integer);
+ INSERT INTO unusual_column_names VALUES (1, 1.0, 0);
+ INSERT INTO unusual_column_names VALUES (2, 2.0, 1);
+ INSERT INTO unusual_column_names VALUES (3, 3.0, 1);
+ GRANT SELECT ON unusual_column_names TO PUBLIC;'''
+ self.server.execute_sql(self.dbname, "admin", stmt)
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ table = PostGISTable(db, 'unusual_column_names')
+
+ self.assertEquals(table.NumColumns(), 3)
+ self.assertEquals(table.Column(0).name, "gid")
+ self.assertEquals(table.Column(1).name, "with space")
+ self.assertEquals(table.Column(2).name, "with \" quote")
+
+ # do some queries where the names have to be quoted
+ self.assertEquals(table.ReadRowAsDict(1),
+ {"gid": 1, "with space": 1.0, "with \" quote": 0})
+ self.assertEquals(table.ReadValue(2, 1, row_is_ordinal = True), 3.0)
+ self.assertEquals(table.ReadValue(2, 1, row_is_ordinal = False), 2.0)
+ self.assertEquals(table.ValueRange("with space"), (1.0, 3.0))
+
+ # The return value of UniqueValues is unsorted, so we need to
+ # sort it for comparison.
+ unique_values = table.UniqueValues("with \" quote")
+ unique_values.sort()
+ self.assertEquals(unique_values, [0, 1])
+ self.assertEquals(table.SimpleQuery(table.Columns()[2], "==", 1),
+ [2, 3])
+ self.assertEquals(table.SimpleQuery(table.Columns()[0], "==",
+ table.Columns()[1]), [1, 2, 3])
+
+ def test_shapestore_name_quoting(self):
+ """Test whether PostGISShapeStore quotes table names properly"""
+ postgissupport.skip_if_addgeometrycolumn_does_not_use_quote_ident()
+
+ # Create a table with a name that needs quoting and a geometry
+ # column whose name has to be quoted
+ stmt = '''CREATE TABLE "table "" name" (gid integer);
+ GRANT SELECT ON "table "" name" TO PUBLIC;'''
+ self.server.execute_sql(self.dbname, "admin", stmt)
+ stmt = """select AddGeometryColumn('%s', 'table \" name',
+ 'the \" geom', '-1', 'POINT', 2);"""
+ self.server.execute_sql(self.dbname, "admin", stmt % self.dbname)
+ stmt = '''INSERT INTO "table "" name" VALUES (0,
+ GeometryFromText('POINT(0 0)', -1));'''
+ self.server.execute_sql(self.dbname, "admin", stmt)
+
+ # Instantiate the table
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ store = PostGISShapeStore(db, "table \" name")
+
+ # do some queries where the names have to be quoted
+ self.assertEquals(store.NumShapes(), 1)
+ self.assertEquals(store.ShapeType(), SHAPETYPE_POINT)
+ self.assertEquals(store.BoundingBox(), (0, 0, 0, 0))
+ self.assertEquals(store.Shape(0).ShapeID(), 0)
+ self.assertEquals([s.ShapeID() for s in store.AllShapes()], [0])
+ self.assertEquals([s.ShapeID()
+ for s in store.ShapesInRegion((-1, -1, 1, 1))], [0])
+
+ def test_shapestore_empty_table(self):
+ """Test PostGISShapeStore with emtpy table"""
+ conn = psycopg.connect("dbname=%s " % self.dbname
+ + self.server.connection_string("admin"))
+ cursor = conn.cursor()
+ cursor.execute("CREATE TABLE test (A INT);")
+ cursor.execute("SELECT AddGeometryColumn(%(dbname)s, 'test',"
+ " 'geometry', -1, 'POINT', 2);",
+ {"dbname": self.dbname})
+ cursor.execute("GRANT SELECT ON test TO PUBLIC;")
+ conn.commit()
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ store = PostGISShapeStore(db, "test")
+ self.assertEquals(store.BoundingBox(), None)
+
+ def test_shapestore_two_geom_cols(self):
+ """Test PostGISShapeStore with two geometry columns"""
+ conn = psycopg.connect("dbname=%s " % self.dbname
+ + self.server.connection_string("admin"))
+ cursor = conn.cursor()
+ cursor.execute("INSERT INTO spatial_ref_sys VALUES"
+ " (1, '', 1, '', 'proj=longlat datum=WGS84')")
+ cursor.execute("INSERT INTO spatial_ref_sys VALUES"
+ " (2, '', 2, '', 'proj=longlat datum=WGS84')")
+
+ cursor.execute("CREATE TABLE two_geom_cols"
+ " (gid INTEGER PRIMARY KEY);")
+ cursor.execute("SELECT AddGeometryColumn(%(dbname)s, 'two_geom_cols',"
+ " 'point', 1, 'POINT', 2);",
+ {"dbname": self.dbname})
+ cursor.execute("SELECT AddGeometryColumn(%(dbname)s, 'two_geom_cols',"
+ " 'poly', 2, 'POLYGON', 2);",
+ {"dbname": self.dbname})
+ cursor.execute("INSERT INTO two_geom_cols(gid, point, poly) VALUES (1,"
+ " GeometryFromText('POINT(1 1)', 1),"
+ " GeometryFromText('POLYGON((1 1, 1 2, 2 2,1 1))',2));")
+ cursor.execute("GRANT SELECT ON two_geom_cols TO PUBLIC;")
+ conn.commit()
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+
+ # The table has two geometry columns, and will raise a TypeError
+ # when instantiated without specifying which one to use.
+ self.assertRaises(TypeError,
+ PostGISShapeStore, db, "two_geom_cols")
+
+ # If the geometry_column is not really a geometry column, we get
+ # a TypeError
+ self.assertRaises(TypeError,
+ PostGISShapeStore, db, "two_geom_cols",
+ geometry_column = "gid")
+
+ # Instantiate two shape stores, one for each of the geometry
+ # columns, and test whether they determine the right shape types
+ # and srids (getting the srid wrong would lead to an exception
+ # in ShapesInRegion).
+ store = PostGISShapeStore(db, "two_geom_cols",
+ geometry_column = "point")
+ self.assertEquals(store.ShapeType(), SHAPETYPE_POINT)
+ self.assertEquals([s.ShapeID()
+ for s in store.ShapesInRegion((0, 0, 100,100))],
+ [1])
+
+ store = PostGISShapeStore(db, "two_geom_cols",
+ geometry_column = "poly")
+ self.assertEquals(store.ShapeType(), SHAPETYPE_POLYGON)
+ self.assertEquals([s.ShapeID()
+ for s in store.ShapesInRegion((0, 0, 100,100))],
+ [1])
+
+
+ def test_simple_error_handling(self):
+ """Test some simple error handling.
+
+ If an error happens in, say the SimpleQuery method, a subsequent
+ ReadValue call should still succeed.
+ """
+ conn = psycopg.connect("dbname=%s " % self.dbname
+ + self.server.connection_string("admin"))
+ cursor = conn.cursor()
+ cursor.execute("CREATE TABLE some_table"
+ " (gid INTEGER PRIMARY KEY, length float);"
+ "INSERT INTO some_table VALUES (1, 3.5);")
+ cursor.execute("GRANT SELECT ON some_table TO PUBLIC;")
+ conn.commit()
+ conn.close()
+
+ db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+ table = PostGISTable(db, "some_table", id_column = "gid")
+
+ # trying to compare the length to a string should fail with an
+ # exception.
+ self.assertRaises(psycopg.ProgrammingError,
+ table.SimpleQuery,
+ table.Column("length"), "<=", "abc")
+
+ # After the exception, doing a query on the same table should
+ # work. Since it's the same database connection as before, it
+ # can fail if no rollback has been done or the connection isn't
+ # in autocommit mode. Typical error message is
+ #
+ # ERROR: current transaction is aborted, commands ignored
+ # until end of transaction block
+ try:
+ self.assertEquals(table.ReadValue(1, "length"), 3.5)
+ except psycopg.ProgrammingError, val:
+ self.fail("table didn't handle exception properly (%s)" % val)
+
+
+class PostGISStaticTests(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Base class for PostGIS tests with static data."""
+
+ def setUp(self):
+ """Start the server and create a database with static data
+
+ This method sets the following instance attributes:
+
+ dbname -- the name of the database
+
+ server -- The server object
+
+ db -- the PostGISConnection object
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.postgisdb = self.server.get_default_static_data_db()
+ self.db = PostGISConnection(dbname = self.postgisdb.dbname,
+ **self.server.connection_params("user"))
+
+ def tearDown(self):
+ """Close the database connection"""
+ self.db.Close()
+
+
+class TableTests:
+
+ """Mix-in class for the PostGISTable tests
+
+ The tests defined here make some assumptions about the table and the
+ data in it:
+
+ self.table should be the PostGISTable instance to test. Derived
+ classes should set this up in setUp.
+
+ self.db should be the DB connection object used by self.table.
+
+ self.table_name should be the name of the table in the database.
+ The tests assume that e.g. the title of self.table can be
+ derived from this.
+
+ self.gid_column should be the name of the gid column used when
+ self.table was instantiated.
+
+ The data in the table should be the data of the
+ cultural_landmark-point shapefile with the shape ids used to get
+ the contents of the gid column by adding 1000.
+ """
+
+ def test_dbconn(self):
+ """Test PostGISTable.DBConnection()"""
+ self.failUnless(self.table.DBConnection() is self.db)
+
+ def test_dbname(self):
+ """Test PostGISTable.TableName()"""
+ self.assertEquals(self.table.TableName(), self.table_name)
+
+ def test_title(self):
+ """test PostGISTable.Title()"""
+ # The title is currently equal to the tablename
+ self.assertEquals(self.table.Title(), self.table_name)
+
+ def test_dependencies(self):
+ """Test PostGISTable.Dependencies()"""
+ # A PostGISTable depends on no other data container
+ self.assertEquals(self.table.Dependencies(), ())
+
+ def test_num_rows(self):
+ """Test PostGISTable.NumRows()"""
+ self.assertEquals(self.table.NumRows(), 34)
+
+ def test_num_columns(self):
+ """Test PostGISTable.NumColumns()"""
+ # The table in the postgis db has one additional column, "gid",
+ # so there's one more column in the PostGISTable than in the DBF
+ self.assertEquals(self.table.NumColumns(), 7)
+
+ def test_columns(self):
+ """Test PostGISTable.Columns()"""
+ self.assertEquals(len(self.table.Columns()), 7)
+ self.assertEquals(self.table.Columns()[0].name, self.gid_column)
+ self.assertEquals(self.table.Columns()[0].type, FIELDTYPE_INT)
+ self.assertEquals(self.table.Columns()[0].index, 0)
+ self.assertEquals(self.table.Columns()[1].name, "area")
+ self.assertEquals(self.table.Columns()[1].type, FIELDTYPE_DOUBLE)
+ self.assertEquals(self.table.Columns()[1].index, 1)
+ self.assertEquals(self.table.Columns()[5].name, "clptlabel")
+ self.assertEquals(self.table.Columns()[5].type, FIELDTYPE_STRING)
+ self.assertEquals(self.table.Columns()[5].index, 5)
+
+ def test_column(self):
+ """Test PostGISTable.Column()"""
+ self.assertEquals(self.table.Column("area").name, "area")
+ self.assertEquals(self.table.Column("area").type, FIELDTYPE_DOUBLE)
+ self.assertEquals(self.table.Column("area").index, 1)
+
+ def test_has_column(self):
+ """Test PostGISTable.HasColumn()"""
+ self.assert_(self.table.HasColumn("area"))
+ self.failIf(self.table.HasColumn("foo"))
+
+ def test_read_row_as_dict(self):
+ """Test PostGISTable.ReadRowAsDict()"""
+ self.assertEquals(self.table.ReadRowAsDict(1003),
+ {self.gid_column: 1003,
+ "area": 0.0,
+ "perimeter": 0.0,
+ "clpoint_": 4,
+ "clpoint_id": 24,
+ "clptlabel": "RUINS",
+ "clptflag": 0})
+
+ def test_read_row_as_dict_row_count_mode(self):
+ """Test PostGISTable.ReadRowAsDict() row count address mode"""
+ self.assertEquals(self.table.ReadRowAsDict(3, row_is_ordinal = 1),
+ {self.gid_column: 1003,
+ "area": 0.0,
+ "perimeter": 0.0,
+ "clpoint_": 4,
+ "clpoint_id": 24,
+ "clptlabel": "RUINS",
+ "clptflag": 0})
+
+ def test_read_value(self):
+ """Test PostGISTable.ReadValue()"""
+ self.assertEquals(self.table.ReadValue(1003, 4), 24)
+ self.assertEquals(self.table.ReadValue(1003, "clpoint_id"), 24)
+
+ def test_read_value_row_count_mode(self):
+ """Test PostGISTable.ReadValue() row count address mode"""
+ self.assertEquals(self.table.ReadValue(3, 4, row_is_ordinal = 1), 24)
+ self.assertEquals(self.table.ReadValue(3, "clpoint_id",
+ row_is_ordinal = 1),
+ 24)
+
+ def test_row_id_to_ordinal(self):
+ """Test PostGISTable.RowIdToOrdinal()"""
+ self.assertEquals(self.table.RowIdToOrdinal(1005), 5)
+
+ def test_row_oridnal_to_id(self):
+ """Test PostGISTable.RowOrdinalToId()"""
+ self.assertEquals(self.table.RowOrdinalToId(5), 1005)
+
+ def test_value_range(self):
+ """Test PostGISTable.ValueRange()"""
+ self.assertEquals(self.table.ValueRange("clpoint_id"), (21, 74))
+
+ def test_unique_values(self):
+ """Test PostGISTable.UniqueValues()"""
+ values = self.table.UniqueValues("clptlabel")
+ values.sort()
+ self.assertEquals(values, ["BUILDING", "FARM", "HUT","LIGHTHOUSE",
+ "OTHER/UNKNOWN", "RUINS"])
+
+ def test_simple_query(self):
+ """Test PostGISTable.SimpleQuery()"""
+ table = self.table
+ self.assertEquals(table.SimpleQuery(table.Column("clptlabel"),
+ "==", "FARM"),
+ [1006])
+ self.assertEquals(table.SimpleQuery(table.Column("clpoint_id"),
+ ">", 70),
+ [1024, 1025, 1026])
+ self.assertEquals(table.SimpleQuery(table.Column("clpoint_id"),
+ "<", table.Column("clpoint_")),
+ [1028, 1029, 1030, 1031, 1032, 1033])
+
+
+class TestPostGISTable(TableTests, PostGISStaticTests):
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISTable"""
+ PostGISStaticTests.setUp(self)
+ self.table_name = "landmarks"
+ self.gid_column = "gid"
+
+ # Note that omit the gid column here to the backwards compatible
+ # interface of the constructor where the gid_column defaults to
+ # "gid"
+ self.table = PostGISTable(self.db, self.table_name)
+
+
+class TestPostGISTableExplicitGIDColumn(TableTests, PostGISStaticTests):
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISTable"""
+ PostGISStaticTests.setUp(self)
+ self.table_name = "landmarks_point_id"
+ self.gid_column = "point_id"
+ self.table = PostGISTable(self.db, self.table_name,
+ id_column = self.gid_column)
+
+
+class PointTests:
+
+ """Mix-in class for the tests on POINT tables
+
+ The methods in this class expect self.store to be the shapestore
+ used for testing. Derived classes should initialize self.store with
+ PostGISShapeStore in setUp. Another assumption is that the data in
+ self.store is effectively the cultural_landmark-point shapefile with
+ shape ids increased by 1000.
+ """
+
+ #
+ # First, some tests that should be independend of the shapetype, so
+ # it shouldn't be necessary to repeat them for other shapetypes
+ #
+
+ def test_dependencies(self):
+ """Test PostGISShapeStore.Dependencies()"""
+ # A PostGISShapeStore depends on no other data container
+ self.assertEquals(self.store.Dependencies(), ())
+
+ def test_table(self):
+ """Test PostGISShapeStore.Table() with POINT shapes"""
+ # A PostGISShapeStore is its own table
+ self.assert_(self.store.Table() is self.store)
+
+ def test_orig_shapestore(self):
+ """Test PostGISShapeStore.OrigShapeStore() with POINT shapes"""
+ # A PostGISShapeStore is not derived from another shape store
+ self.assert_(self.store.OrigShapeStore() is None)
+
+ def test_raw_format(self):
+ """Test PostGISShapeStore.RawShapeFormat() with POINT shapes"""
+ self.assertEquals(self.store.RawShapeFormat(), RAW_WKT)
+
+ def test_all_shapes(self):
+ """Test PostGISShapeStore.AllShapes()"""
+ self.assertEquals([s.ShapeID() for s in self.store.AllShapes()],
+ range(1000, 1000 + self.store.NumShapes()))
+
+ def test_id_column(self):
+ self.assertEquals(self.store.IDColumn().name, self.id_column)
+
+ def test_geometry_column(self):
+ self.assertEquals(self.store.GeometryColumn().name,
+ self.geometry_column)
+
+ #
+ # Shapetype specific tests
+ #
+
+ def test_shape_type(self):
+ """Test PostGISShapeStore.ShapeType() with POINT shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_POINT)
+
+ def test_num_shapes(self):
+ """Test PostGISShapeStore.NumShapes() with POINT shapes"""
+ self.assertEquals(self.store.NumShapes(), 34)
+
+ def test_bounding_box(self):
+ """Test PostGISShapeStore.BoundingBox() with POINT shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-23.806047439575195, 63.405960083007812,
+ -15.12291431427002, 66.36572265625])
+
+ def test_shape_shapeid(self):
+ """Test PostGISShapeStore.Shape(i).ShapeID() with POINT shapes"""
+ self.assertEquals(self.store.Shape(1005).ShapeID(), 1005)
+
+ def test_shape_points(self):
+ """Test PostGISShapeStore.Shape(i).Points() with POINT shapes"""
+ self.assertPointListEquals(self.store.Shape(1000).Points(),
+ [[(-22.711074829101562, 66.36572265625)]])
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with POINT shapes"""
+ self.assertEquals(self.store.Shape(1000).RawData(),
+ 'POINT(-22.7110748291016 66.36572265625)')
+
+ def test_shapes_in_region(self):
+ """Test PostGISShapeStore:ShapesInRegion() with POINT shapes"""
+ shapes = self.store.ShapesInRegion((-20.0, 64.0, -24.0, 67))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [1000, 1001, 1002, 1003, 1004, 1005, 1027])
+
+
+class TestPostGISShapestorePoint(PointTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with POINT data an no SRID"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.id_column = "gid"
+ self.geometry_column = "the_geom"
+ self.store = PostGISShapeStore(self.db, "landmarks")
+
+
+
+class TestPostGISShapestorePointSRID(PointTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with POINT data and an SRID"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.id_column = "gid"
+ self.geometry_column = "the_geom"
+ self.store = PostGISShapeStore(self.db, "landmarks_srid")
+
+
+class TestPostGISShapestorePointExplicitGIDColumn(PointTests,
+ PostGISStaticTests):
+
+ """Tests for PostGISShapeStores with POINT data and explicit gid column"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.id_column = "point_id"
+ self.geometry_column = "the_geom"
+ self.store = PostGISShapeStore(self.db, "landmarks_point_id",
+ id_column = "point_id")
+
+
+class TestPostGISShapestorePointOIDAsGIDColumn(PointTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStores with POINT data using OID as gid column"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.id_column = "oid"
+ self.geometry_column = "the_geom"
+ self.store = PostGISShapeStore(self.db, "landmarks_point_id",
+ id_column = self.id_column,
+ geometry_column = self.geometry_column)
+
+ def find_test_shape_id(self):
+ """Return the id of an interesting shape for some test cases.
+
+ This test uses OIDs so we can't easily hard wire ids in the test
+ cases
+ """
+ # get the id of an interesting shape
+ shapes = self.store.ShapesInRegion((-20.0, 64.0, -24.0, 67))
+ return list(shapes)[0].ShapeID()
+
+
+ # Override a few tests that won't work with this table because they
+ # require knowledge of specific IDs
+
+ def test_shape_shapeid(self):
+ """Test PostGISShapeStore.Shape(i).ShapeID() with POINT shapes"""
+ gid = self.find_test_shape_id()
+ self.assertEquals(self.store.Shape(gid).ShapeID(), gid)
+
+ def test_shape_points(self):
+ """Test PostGISShapeStore.Shape(i).Points() with POINT shapes"""
+ gid = self.find_test_shape_id()
+ self.assertPointListEquals(self.store.Shape(gid).Points(),
+ [[(-22.711074829101562, 66.36572265625)]])
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with POINT shapes"""
+ gid = self.find_test_shape_id()
+ self.assertEquals(self.store.Shape(gid).RawData(),
+ 'POINT(-22.7110748291016 66.36572265625)')
+
+ def test_shapes_in_region(self):
+ """Test PostGISShapeStore:ShapesInRegion() with POINT shapes"""
+ shapes = self.store.ShapesInRegion((-20.0, 64.0, -24.0, 67))
+ self.assertEquals(len(list(shapes)), 7)
+
+ def test_all_shapes(self):
+ """Test PostGISShapeStore.AllShapes()"""
+ self.assertEquals(len(list(self.store.AllShapes())), 34)
+
+
+class TestPostGISShapestorePointFromViews(PointTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStores with POINT data in a view"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.id_column = "point_id"
+ self.geometry_column = "the_geom"
+ self.store = PostGISShapeStore(self.db, "v_landmarks",
+ id_column = "point_id")
+
+
+class LineStringTests:
+
+ """Tests shared by the LINESTRING and MULTILINESTRING tests.
+
+ The tests are the same because they are based on the same data.
+ """
+
+ def test_shape_type(self):
+ """Test PostGISShapeStore.ShapeType() with ARC shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_ARC)
+
+ def test_num_shapes(self):
+ """Test PostGISShapeStore.NumShapes() with ARC shapes"""
+ self.assertEquals(self.store.NumShapes(), 839)
+
+ def test_bounding_box(self):
+ """Test PostGISShapeStore.BoundingBox() with ARC shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+
+ def test_shape_shapeid(self):
+ """Test PostGISShapeStore.Shape(i).ShapeID() with ARC shapes"""
+ self.assertEquals(self.store.Shape(5).ShapeID(), 5)
+
+ def test_shape_points(self):
+ """Test PostGISShapeStore.Shape(i).Points() with ARC shapes"""
+ self.assertPointListEquals(self.store.Shape(32).Points(),
+ [[(-15.0821743011474, 66.2773818969726),
+ (-15.0263500213623, 66.2733917236328)]])
+
+ def test_shapes_in_region(self):
+ """Test PostGISShapeStore.ShapesInRegion() with ARC shapes"""
+ shapes = self.store.ShapesInRegion((-24.0, 64.5, -23.5, 65.0))
+ self.assertEquals([s.ShapeID() for s in shapes], [573, 581, 613])
+
+
+class TestPostGISShapestoreLineString(LineStringTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with LINESTRING data"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.store = PostGISShapeStore(self.db, "roads")
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with ARC shapes"""
+ self.assertEquals(self.store.Shape(32).RawData(),
+ "LINESTRING(-15.0821743011475 66.2773818969727,"
+ "-15.0263500213623 66.2733917236328)")
+
+
+class TestPostGISShapestoreMultiLineString(LineStringTests,
+ PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with MULTILINESTRING data"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.store = PostGISShapeStore(self.db, "roads_multi")
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with ARC shapes"""
+ self.assertEquals(self.store.Shape(32).RawData(),
+ "MULTILINESTRING((-15.0821743011475 66.2773818969727,"
+ "-15.0263500213623 66.2733917236328))")
+
+
+class PolygonTests:
+
+ """Test shared by the POLYGON and MULTIPOLYGON tests
+
+ The tests are the same because they are based on the same data.
+ """
+
+ def test_shape_type(self):
+ """Test PostGISShapeStore.ShapeType() with POLYGON shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_POLYGON)
+
+ def test_num_shapes(self):
+ """Test PostGISShapeStore.NumShapes() with POLYGON shapes"""
+ self.assertEquals(self.store.NumShapes(), 156)
+
+ def test_bounding_box(self):
+ """Test PostGISShapeStore.BoundingBox() with POLYGON shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-24.546524047851562, 63.286754608154297,
+ -13.495815277099609, 66.563774108886719])
+
+ def test_shape_shapeid(self):
+ """Test PostGISShapeStore.Shape(i).ShapeID() with POLYGON shapes"""
+ self.assertEquals(self.store.Shape(5).ShapeID(), 5)
+
+ def test_shape_points(self):
+ """Test PostGISShapeStore.Shape(i).Points() with POLYGON shapes"""
+ self.assertPointListEquals(self.store.Shape(4).Points(),
+ [[(-22.40639114379882, 64.714111328125),
+ (-22.41621208190918, 64.716003417968),
+ (-22.40605163574218, 64.719200134277),
+ (-22.40639114379882, 64.714111328125)]])
+
+ def test_shapes_in_region(self):
+ """Test PostGISShapeStore.ShapesInRegion() with POLYGON shapes"""
+ shapes = self.store.ShapesInRegion((-23.0, 65.5, -22.8, 65.25))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [47, 56, 59, 61, 62, 71, 144])
+
+
+class TestPostGISShapestorePolygon(PolygonTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with POLYGON data"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.store = PostGISShapeStore(self.db, "political")
+
+ def test_shape_type(self):
+ """Test PostGISShapeStore.ShapeType() with POLYGON shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_POLYGON)
+
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with POLYGON shapes"""
+ self.assertEquals(self.store.Shape(4).RawData(),
+ "POLYGON((-22.4063911437988 64.714111328125,"
+ "-22.4162120819092 64.7160034179688,"
+ "-22.4060516357422 64.7192001342773,"
+ "-22.4063911437988 64.714111328125))")
+
+
+class TestPostGISShapestoreMultiPolygon(PolygonTests, PostGISStaticTests):
+
+ """Tests for PostGISShapeStore objects with MUTLIPOLYGON data"""
+
+ def setUp(self):
+ """Extend inherited method to set self.table to a PostGISShapeStore"""
+ PostGISStaticTests.setUp(self)
+ self.store = PostGISShapeStore(self.db, "political_multi")
+
+ def test_shape_raw_data(self):
+ """Test PostGISShapeStore.Shape(i).RawData() with POLYGON shapes"""
+ self.assertEquals(self.store.Shape(4).RawData(),
+ "MULTIPOLYGON(((-22.4063911437988 64.714111328125,"
+ "-22.4162120819092 64.7160034179688,"
+ "-22.4060516357422 64.7192001342773,"
+ "-22.4063911437988 64.714111328125)))")
+
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_postgis_session.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_postgis_session.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_postgis_session.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,132 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test PostGISConnection and Session interaction"""
+
+__version__ = "$Revision: 1634 $"
+# $Source$
+# $Id: test_postgis_session.py 1634 2003-08-22 16:55:19Z bh $
+
+import unittest
+
+import postgissupport
+import support
+support.initthuban()
+
+from Thuban.Model.postgisdb import PostGISConnection
+from Thuban.Model.session import Session
+from Thuban.Model.messages import DBCONN_ADDED, DBCONN_REMOVED
+
+class TestSessionWithPostGIS(unittest.TestCase, support.SubscriberMixin):
+
+ def setUp(self):
+ """Start the server and create a database.
+
+ The database name will be stored in self.dbname, the server
+ object in self.server and the db object in self.db.
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.dbref = self.server.get_default_static_data_db()
+ self.dbname = self.dbref.dbname
+ self.session = Session("PostGIS Session")
+ self.db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+
+ self.session.Subscribe(DBCONN_ADDED,
+ self.subscribe_with_params, DBCONN_ADDED)
+ self.session.Subscribe(DBCONN_REMOVED,
+ self.subscribe_with_params, DBCONN_REMOVED)
+ self.clear_messages()
+
+ def tearDown(self):
+ self.session.Destroy()
+ self.clear_messages()
+
+ def test_add_dbconn(self):
+ """Test Session.AddDBConnection()"""
+ # Sanity check. No messages should have been generated so far
+ self.check_messages([])
+
+ self.session.AddDBConnection(self.db)
+
+ # After the connection has been added it should show up in the
+ # list returned by DBConnections and a DBCONN_ADDED message
+ # should have been sent
+ self.assertEquals(self.session.DBConnections(), [self.db])
+ self.check_messages([(DBCONN_ADDED,)])
+
+ def test_remove_dbconn(self):
+ """Test Session.RemoveDBConnection()"""
+ self.session.AddDBConnection(self.db)
+ self.clear_messages()
+ self.session.RemoveDBConnection(self.db)
+
+ # After the connection has been added it should not show up in
+ # the list returned by DBConnections any more and a
+ # DBCONN_REMOVED message should have been sent
+ self.assertEquals(self.session.DBConnections(), [])
+ self.check_messages([(DBCONN_REMOVED,)])
+
+ def test_remove_dbconn_exception(self):
+ """Test Session.RemoveDBConnection() with unknown connection"""
+ self.session.AddDBConnection(self.db)
+ self.clear_messages()
+
+ # Trying to remove an unknown connection will raise a
+ # ValueError.
+ self.assertRaises(ValueError, self.session.RemoveDBConnection,
+ PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user")))
+ # No message should have been sent when the removal fails
+ self.check_messages([])
+
+ def test_open_db_shapestore(self):
+ """Test Session.OpenDBShapeStore()"""
+ self.session.AddDBConnection(self.db)
+ store = self.session.OpenDBShapeStore(self.db, "landmarks")
+ self.assertEquals(store.NumShapes(), 34)
+
+ def test_remove_dbconn_still_in_use(self):
+ """Test Session.RemoveDBConnection() with connectin still in use"""
+ self.session.AddDBConnection(self.db)
+ store = self.session.OpenDBShapeStore(self.db, "landmarks")
+
+ # Removing a db connection that's still in use raises a
+ # ValueError (not sure the choice of ValueError is really good
+ # here).
+ self.assertRaises(ValueError, self.session.RemoveDBConnection, self.db)
+
+ def test_can_remove_db_con(self):
+ """Test Session.CanRemoveDBConnection()"""
+ self.session.AddDBConnection(self.db)
+ store = self.session.OpenDBShapeStore(self.db, "landmarks")
+
+ # The db connection is in use by store, so CanRemoveDBConnection
+ # should return false
+ self.failIf(self.session.CanRemoveDBConnection(self.db))
+
+ # The only reference to the shapestore is in store, so deleting
+ # the it should remove the weak reference kept by the session so
+ # that afterwards CanRemoveDBConnection should return true
+ del store
+
+ self.failUnless(self.session.CanRemoveDBConnection(self.db))
+
+ def test_has_db_conections(self):
+ """Test Session.HasDBConnections()"""
+ self.failIf(self.session.HasDBConnections())
+
+ self.session.AddDBConnection(self.db)
+ self.failUnless(self.session.HasDBConnections())
+
+ self.session.RemoveDBConnection(self.db)
+ self.failIf(self.session.HasDBConnections())
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_proj.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_proj.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_proj.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,506 @@
+# Copyright (c) 2002, 2003, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Thuban-specific Projection class
+"""
+
+__version__ = "$Revision: 2698 $"
+# $Source$
+# $Id: test_proj.py 2698 2006-09-18 00:56:26Z bernhard $
+
+import unittest
+import locale
+import os
+
+import localessupport
+import xmlsupport
+import support
+support.initthuban()
+
+from Thuban import _
+from Thuban.Model.proj import Projection, ProjFile, \
+ PROJ_UNITS_METERS, PROJ_UNITS_DEGREES
+from Thuban.Model.messages import PROJECTION_ADDED, PROJECTION_REMOVED, \
+ PROJECTION_REPLACED
+import Thuban.Model.resource as resource
+
+from xmlsupport import sax_eventlist
+
+from xml.sax import SAXParseException
+
+
+class TestProjection(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Test cases for the Thuban-specific Projection class
+ """
+
+ def test(self):
+ """Test Projection"""
+ params = ["zone=26", "proj=utm", "ellps=clrk66"]
+ proj = Projection(params)
+ self.assertEquals(proj.params, params)
+
+ # It's not clear whether this value is really the correct one
+ # but a test failure here probably still means a bug somewhere
+ self.assertFloatSeqEqual(proj.Forward(0, 0),
+ [3623101.8103431347, 0.0],
+ epsilon = 1e-5)
+ self.assertFloatSeqEqual(proj.Inverse(3623101.8103431347, 0.0),
+ [-0.00065775699878736467, 0])
+
+ self.assertFloatSeqEqual(proj.ForwardBBox((0, 0, 2, 2)),
+ (3620891.3077618643, 0.0,
+ 3875381.8535437919, 252962.10480170773),
+ epsilon = 1e-5)
+ self.assertFloatSeqEqual(proj.InverseBBox((3620891.3077618643, 0.0,
+ 3875381.8535437919,
+ 252962.10480170773)),
+ (-0.018341599754143501, 0.0,
+ 2.017992992681688, 2.0377390677846736),
+ epsilon = 1e-5)
+
+ # GetName()
+ self.assertEquals(proj.GetName(), _("Unknown"))
+
+ # GetParameter()
+ self.assertEquals(proj.GetParameter("zone"), "26")
+ self.assertEquals(proj.GetParameter("proj"), "utm")
+ self.assertEquals(proj.GetParameter("ellps"), "clrk66")
+ self.assertEquals(proj.GetParameter("hallo"), "")
+
+ # GetAllParameters()
+ self.assertEquals(proj.GetAllParameters(), params)
+
+ # GetName()
+ proj = Projection(params, "MyName")
+ self.assertEquals(proj.GetName(), "MyName")
+
+ def test_get_parameter_without_equals_sign(self):
+ """Test Projection.GetParameter() for a parameter without '=' sign"""
+ proj = Projection(["proj=utm", "zone=34", "south", "ellps=clrk66"])
+ # The Projection class pretends that for parameters specified
+ # without a value the value is the same as the parameter name.
+ self.assertEquals(proj.GetParameter("south"), "south")
+
+ def test_get_projection_units_geo(self):
+ """Test Projection.GetProjectedUnits() for geographic projection.
+ Test for the alias 'longlat' as well.
+ """
+ proj = Projection(["proj=latlong", "to_meter=0.017453292519943295",
+ "ellps=clrk66"])
+ self.assertEquals(proj.GetProjectedUnits(), PROJ_UNITS_DEGREES)
+ proj = Projection(["proj=longlat", "to_meter=0.017453292519943295",
+ "ellps=clrk66"])
+ self.assertEquals(proj.GetProjectedUnits(), PROJ_UNITS_DEGREES)
+
+ def test_lc_numeric_robustness(self):
+ """Test if an LC_NUMERIC local with comma as decimal_point will work.
+
+ Some versions of proj are not robust against this.
+ Starting with Python 2.4 there is a different behaviour when
+ calling C extensions and now they will see changes locales settings
+ which might tickle the bug in proj.
+ """
+ params = ["proj=latlong", "to_meter=0.01745", "ellps=clrk66"]
+
+ oldlocale = localessupport.setdecimalcommalocale()
+ if oldlocale == None:
+ raise support.SkipTest(
+ "No locale with comma as decimal_point found.")
+
+ proj = Projection(params)
+ #print proj.work_around_broken_proj
+ result1 = proj.Forward(1.2,3.2)
+
+ locale.setlocale(locale.LC_NUMERIC, "C")
+ proj = Projection(params)
+ result2= proj.Forward(1.2,3.2)
+
+ locale.setlocale(locale.LC_NUMERIC, oldlocale)
+ self.assertFloatSeqEqual(result1, result2, epsilon = 1e-5 )
+
+ def test_get_projection_units_normal(self):
+ """Test Projection.GetProjectedUnits() for normal projection"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.assertEquals(proj.GetProjectedUnits(), PROJ_UNITS_METERS)
+
+ def test_label(self):
+ """Test Projection.Label() without epsg"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"],
+ name = "My Projection")
+ self.assertEquals(proj.Label(), "My Projection")
+
+ def test_label_epsg(self):
+ """Test Projection.Label() with epsg"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"],
+ name = "My Projection", epsg="42")
+ self.assertEquals(proj.Label(), "EPSG 42 My Projection")
+
+ def test_epsgcode_for_non_epsg_projection(self):
+ """Test Projection.EPSGCode() without epsg"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"],
+ name = "My Projection")
+ self.assertEquals(proj.EPSGCode(), None)
+
+ def test_epsgcode_for_real_epsg_projection(self):
+ """Test Projection.EPSGCode() with epsg"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"],
+ name = "My Projection", epsg="42")
+ self.assertEquals(proj.EPSGCode(), "42")
+
+
+
+class TestProjFileSimple:
+
+ def test_init(self):
+ """Test ProjFile coinstructor"""
+ proj_file = ProjFile("some_filename")
+ self.assertEquals(proj_file.GetFilename(), "some_filename")
+ self.assertEquals(len(proj_file.GetProjections()), 0)
+
+ def test_set_filename(self):
+ """Test ProjFile.SetFilename()"""
+ proj_file = ProjFile("some_filename")
+ proj.SetFilename("other_name")
+ self.assertEquals(proj_file.GetFilename(), "other_name")
+
+
+class TestProjFile(unittest.TestCase, support.SubscriberMixin):
+
+ """Test cases for ProjFile objects"""
+
+ def setUp(self):
+ self.clear_messages()
+ self.proj0 = Projection(["proj=tmerc", "ellps=clrk66"])
+ self.proj1 = Projection(["proj=utm", "ellps=clrk66"])
+ self.proj2 = Projection(["proj=lcc", "ellps=clrk66",
+ "lat_1=0", "lat_2=20"])
+ self.proj_file = ProjFile("some_filename")
+ for msg in [PROJECTION_ADDED, PROJECTION_REMOVED, PROJECTION_REPLACED]:
+ self.proj_file.Subscribe(msg, self.subscribe_with_params, msg)
+
+ def tearDown(self):
+ self.clear_messages()
+ self.proj_file.Destroy()
+
+ def test_add_remove(self):
+ """Test ProjFile.Add() and ProjFile.Remove()"""
+ self.proj_file.Add(self.proj0)
+ self.proj_file.Add(self.proj1)
+ self.assertEquals(self.proj_file.GetProjections(),
+ [self.proj0, self.proj1])
+ self.check_messages([(self.proj0, PROJECTION_ADDED),
+ (self.proj1, PROJECTION_ADDED)])
+ self.clear_messages()
+
+ self.proj_file.Remove(self.proj0)
+ self.assertEquals(self.proj_file.GetProjections(), [self.proj1])
+ self.check_messages([(self.proj0, PROJECTION_REMOVED)])
+
+ def test_remove_non_existing(self):
+ """Test ProjFile.Remove(<proj not in projfile>)"""
+ self.assertRaises(ValueError, self.proj_file.Remove, self.proj0)
+ # Nothing happened, so no messages should have been sent
+ self.check_messages([])
+
+ def test_replace(self):
+ """Test ProjFile.Replace()"""
+ self.proj_file.Add(self.proj0)
+ self.proj_file.Add(self.proj1)
+ self.clear_messages()
+
+ # Replace()
+ self.proj_file.Replace(self.proj0, self.proj2)
+ self.assertEquals(self.proj_file.GetProjections(),
+ [self.proj2, self.proj1])
+ self.check_messages([(self.proj0, self.proj2, PROJECTION_REPLACED)])
+
+ def test_replace_non_existing(self):
+ """Test ProjFile.Replace(<proj not in projfile>, <some proj>)"""
+ self.proj_file.Add(self.proj0)
+ self.proj_file.Add(self.proj1)
+ self.clear_messages()
+ self.assertRaises(ValueError,
+ self.proj_file.Replace, self.proj2, self.proj0)
+ # All projections should still be there
+ self.assertEquals(self.proj_file.GetProjections(),
+ [self.proj0, self.proj1])
+ # Nothing happened, so no messages should have been sent
+ self.check_messages([])
+
+
+class ProjFileTest(unittest.TestCase, support.FileTestMixin,
+ xmlsupport.ValidationTest):
+
+ """Base class for the proj file tests that read or write files"""
+
+ def filename(self):
+ """Return the filename for the test"""
+ return self.temp_file_name(self.id() + ".proj")
+
+
+class ProjFileReadTests(ProjFileTest):
+
+ """Test read ProjFile objects from files
+
+ The files only cover error handling and the system projection file.
+ """
+
+ def test_read_non_existing_file(self):
+ """Test read_proj_file with non-existing file"""
+ self.assertRaises(IOError,
+ resource.read_proj_file,
+ self.temp_file_name("nonexistent.proj"))
+
+ def test_read_unreadable_file(self):
+ """Test read_proj_file with unreadable file
+
+ As currently written this only works on unix-like systems and
+ not e.g. on MS Windows.
+ """
+ if os.name != "posix":
+ raise support.SkipTest("Test only works on posix systems")
+ filename = self.filename()
+ file = open(filename, "w")
+ file.close()
+ os.chmod(filename, 0200) # write-only
+ self.assertRaises(IOError, resource.read_proj_file, filename)
+
+ def test_read_empty_file(self):
+ """Test read_proj_file with empty file"""
+ filename = self.filename()
+ file = open(filename, "w")
+ file.close()
+
+ self.assertRaises(SAXParseException, resource.read_proj_file, filename)
+
+ def test_get_system_proj_file(self):
+ """Test resource.get_system_proj_file(DEFAULT_PROJ_FILE)
+
+ This is primarily to test whether the system proj file contains
+ invalid projection paramers and whether the proj file is not
+ empty
+ """
+ projfile, warnings\
+ = resource.get_system_proj_file(resource.DEFAULT_PROJ_FILE)
+ self.assertEquals(warnings, [])
+ self.assert_(len(projfile.GetProjections()) > 0)
+
+ # see whether it got cached and we get the same projfile object
+ # when we read the file again
+ projfile2, warnings \
+ = resource.get_system_proj_file(resource.DEFAULT_PROJ_FILE)
+ self.assert_(projfile is projfile2)
+
+
+class WriteProjFileTests(ProjFileTest):
+
+ """Test cases for writing proj files"""
+
+ def compare_xml(self, xml1, xml2):
+ self.assertEquals(sax_eventlist(xml1), sax_eventlist(xml2))
+
+ def doTestWrite(self, projfile, expected):
+ filename = self.filename()
+
+ resource.write_proj_file(projfile)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ self.compare_xml(written_contents, expected)
+ self.validate_data(written_contents)
+ self.validate_data(expected)
+
+ def test_write(self):
+ """Test write_proj_file"""
+ pf = ProjFile(self.filename())
+ pf.Add(Projection(['proj=tmerc', 'ellps=clrk66',
+ 'lat_0=90w', 'lon_0=90w', 'k=1'],
+ "Transverse Mercator",))
+ pf.Add(Projection(["proj=tmerc",
+ "lat_0=0.000000000", "lon_0=-62.000000000",
+ "k=0.999500", "x_0=400000.000", "y_0=0.000",
+ "ellps=clrk80", "units=m"],
+ "Anguilla 1957 / British West Indies Grid",
+ epsg="200"))
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+ <projectionlist>
+ <projection name="Transverse Mercator">
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="lat_0=90w"/>
+ <parameter value="lon_0=90w"/>
+ <parameter value="k=1"/>
+ </projection>
+ <projection epsg="200"
+ name="Anguilla 1957 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.000000000"/>
+ <parameter value="lon_0=-62.000000000"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000.000"/>
+ <parameter value="y_0=0.000"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ </projection>
+ </projectionlist>
+ '''
+ self.doTestWrite(pf, file_contents)
+
+ def test_write_empty_file(self):
+ """Test write empty ProjFile"""
+ pf = ProjFile(self.filename())
+ file_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+ <projectionlist>
+ </projectionlist>
+ '''
+ self.doTestWrite(pf, file_contents)
+
+
+class ProjFileLoadTestCase(support.FileLoadTestCase):
+
+ """Base class for the test cases that read specific test files"""
+
+ file_extension = ".proj"
+
+ def tearDown(self):
+ """Clear the cache explicitly"""
+ resource.clear_proj_file_cache()
+
+
+class TestLoadingProjFile(ProjFileLoadTestCase):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+<projectionlist>
+ <projection name="Transverse Mercator">
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="lat_0=90w"/>
+ <parameter value="lon_0=90w"/>
+ <parameter value="k=1"/>
+ </projection>
+ <projection epsg="200" name="Anguilla 1957 / British West Indies Grid">
+ <parameter value="proj=tmerc"/>
+ <parameter value="lat_0=0.000000000"/>
+ <parameter value="lon_0=-62.000000000"/>
+ <parameter value="k=0.999500"/>
+ <parameter value="x_0=400000.000"/>
+ <parameter value="y_0=0.000"/>
+ <parameter value="ellps=clrk80"/>
+ <parameter value="units=m"/>
+ </projection>
+</projectionlist>
+'''
+
+ def check_projection(self, proj, label, parameters):
+ """Check the values of the proj's label and parameters"""
+ self.assertEquals(proj.Label(), label)
+ params = proj.GetAllParameters()[:]
+ params.sort()
+ self.assertEquals(params, parameters)
+
+ def test(self):
+ projfile, warnings = resource.read_proj_file(self.filename())
+ # no warnings
+ self.assertEquals(warnings, [])
+
+ # There are two projections
+ projs = projfile.GetProjections()
+ self.assertEquals(len(projs), 2)
+
+ self.check_projection(projs[0],
+ "Transverse Mercator",
+ ['ellps=clrk66', 'k=1', 'lat_0=90w', 'lon_0=90w',
+ 'proj=tmerc'])
+ self.check_projection(projs[1],
+ "EPSG 200 Anguilla 1957 / British West Indies Grid",
+ ["ellps=clrk80", "k=0.999500",
+ "lat_0=0.000000000", "lon_0=-62.000000000",
+ "proj=tmerc", "units=m",
+ "x_0=400000.000", "y_0=0.000"])
+
+ def test_caching(self):
+ # test whether the projfile cache works
+ projfile, warnings = resource.read_proj_file(self.filename())
+ projfile2, warnings = resource.read_proj_file(self.filename())
+
+ # Both projfiles should be the same object
+ self.assert_(projfile2 is projfile)
+
+ # If we clear the cache we should get a new one.
+ resource.clear_proj_file_cache()
+ projfile3, warnings = resource.read_proj_file(self.filename())
+ self.assert_(projfile3 is not projfile)
+
+
+class TestLoadingProjFileWithEmptyProjectionlist(ProjFileLoadTestCase):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+<projectionlist>
+</projectionlist>
+'''
+
+ def test(self):
+ projfile, warnings = resource.read_proj_file(self.filename())
+ # no warnings
+ self.assertEquals(warnings, [])
+
+ # There are no projections
+ self.assertEquals(len(projfile.GetProjections()), 0)
+
+
+class TestProjFileWithInvalidParameters(ProjFileLoadTestCase):
+
+ file_contents = '''\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE projectionlist SYSTEM "projfile.dtd">
+<projectionlist>
+ <projection name="Universal Transverse Mercator">
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ <!-- an invalid zone number to trigger the parameter checking
+ in the proj library -->
+ <parameter value="zone=1000"/>
+ </projection>
+ <projection name="Transverse Mercator">
+ <parameter value="proj=tmerc"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="lat_0=90w"/>
+ <parameter value="lon_0=90w"/>
+ <parameter value="k=1"/>
+ </projection>
+</projectionlist>
+'''
+
+ def setUp(self):
+ support.FileLoadTestCase.setUp(self)
+
+ def test(self):
+ """Test reading a proj file with invalid parameters"""
+ projfile, warnings = resource.read_proj_file(self.filename())
+ projs = projfile.GetProjections()
+ self.assertEquals(len(projs), 1)
+ params = projs[0].GetAllParameters()[:]
+ params.sort()
+ self.assertEquals(params, ['ellps=clrk66', 'k=1', 'lat_0=90w',
+ 'lon_0=90w', 'proj=tmerc'])
+ self.assertEquals(warnings,
+ ['Error in projection "Universal Transverse Mercator":'
+ ' invalid UTM zone number'])
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_range.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_range.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_range.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2002, 2003 by Intevation GmbH
+# Authors:
+# Thomas Koester <tkoester at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""
+Unit test for range.py
+"""
+
+__version__ = "$Revision: 1421 $"
+# $Source$
+# $Id: test_range.py 1421 2003-07-15 14:46:55Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.range import Range, _inf
+
+class RangeTest(unittest.TestCase, support.FloatComparisonMixin):
+
+ def test_equal(self):
+ """test if different ways to create a range yield equal ranges"""
+ range = Range()
+ self.assertEqual(range, Range(''))
+ self.assertEqual(range, Range(']-oo;oo['))
+ self.assertEqual(range, Range((']', -_inf, _inf, '[')))
+ self.assertEqual(range, Range((']', '-oo', 'oo', '[')))
+ range = Range('[0;1]')
+ self.assertEqual(range, Range('[000;1.0]'))
+ self.assertEqual(range, Range(('[', '0', 1.0, ']')))
+ range2 = range
+ self.assertEqual(range, range2)
+ range3 = Range(range)
+ self.assertEqual(range3, range2)
+ range = Range(']0;99]')
+ self.assertEqual(range, Range(']0;99E+00]'))
+ self.assertEqual(range, Range(']0;9.9E+01]'))
+ self.assertEqual(range, Range(']0;990E-01]'))
+ self.assertEqual(range, Range(']0;.99E+02]'))
+ self.assertEqual(range, Range((']', 0, '.99E+02', ']')))
+
+ def test_different(self):
+ """test if different ranges are different"""
+ range = Range('[-1;1]')
+ self.failIfEqual(range, Range(']-1;1]'))
+ self.failIfEqual(range, Range('[-1;1['))
+ self.failIfEqual(range, Range(']-1;1['))
+ self.failIfEqual(range, Range('[0;1]'))
+ self.failIfEqual(range, Range('[-1;0]'))
+
+ def test_contains(self):
+ """test value in range"""
+ range = Range((']', '0', 99, ']'))
+ for value in [-0.1, 0, 99.1]:
+ self.failIf(value in range)
+ for value in [0.1, 9.9, 99]:
+ self.assert_(value in range)
+ range = Range('[-oo;0]')
+ for value in [0.1, float('1e100'), float('1e10000')]:
+ self.failIf(value in range)
+ for value in [0.0, float('-1e100'), float('-1e10000')]:
+ self.assert_(value in range)
+
+ def test_float(self):
+ """test string to float conversion"""
+ range = Range()
+ self.assertFloatEqual(range.float('oo'), _inf)
+ self.assertFloatEqual(range.float('-oo'), -_inf)
+ for value in [-100000000000000000000l, 12345.6789, 0, 0.0, 5.30e20]:
+ self.assertFloatEqual(range.float(str(value)), value)
+
+ def test_short_range(self):
+ """test if range parser handles short ranges"""
+ range = Range('[0;0]')
+ self.failIf(-0.001 in range)
+ self.assert_(0 in range)
+ self.failIf(0.001 in range)
+
+ def test_bad_ranges(self):
+ """test if range parser raises correct exception on bad ranges"""
+ for range in [0, 1.1]:
+ self.assertRaises(TypeError, Range, range)
+ for range in ['x', ']x;9]', ']]0;1]', '[0;1]]', '[0;x]', '0',
+ '[0]', '[;]', '[0;]', '[;0]', '[1;0]',
+ ']0;0]', '[0;0[', ']0;0[',
+ ('[',), ('[', 0), ('[', 0, 1), ('[', 0, ']'),
+ ('', 0, 1, ']'), ('[', 0, 1, '')]:
+ self.assertRaises(ValueError, Range, range)
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_save.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_save.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_save.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,645 @@
+# Copyright (c) 2002, 2003, 2004, 2005 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test saving a thuban session as XML
+"""
+
+__version__ = "$Revision: 2688 $"
+# $Source$
+# $Id: test_save.py 2688 2006-06-30 12:27:20Z frank $
+
+import os
+import unittest
+from StringIO import StringIO
+
+import xmlsupport
+import postgissupport
+
+import support
+support.initthuban()
+
+import dbflib
+
+from Thuban import internal_from_unicode
+from Thuban.Lib.fileutil import relative_filename
+from Thuban.Model.save import XMLWriter, save_session, sort_data_stores
+from Thuban.Model.session import Session
+from Thuban.Model.map import Map
+from Thuban.Model.layer import Layer, RasterLayer
+from Thuban.Model.proj import Projection
+from Thuban.Model.table import DBFTable
+from Thuban.Model.transientdb import TransientJoinedTable
+from Thuban.Model.data import DerivedShapeStore, SHAPETYPE_ARC
+
+from Thuban.Model.classification import ClassGroupSingleton, ClassGroupRange, \
+ ClassGroupPattern, ClassGroupProperties
+
+from Thuban.Model.range import Range
+
+from Thuban.Model.postgisdb import PostGISConnection, PostGISShapeStore
+
+
+class XMLWriterTest(unittest.TestCase):
+
+ def testEncode(self):
+ """Test XMLWriter.encode"""
+ writer = XMLWriter()
+ eq = self.assertEquals
+
+ eq(writer.encode("hello world"), "hello world")
+ eq(writer.encode(unicode("hello world")), unicode("hello world"))
+
+ eq(writer.encode(internal_from_unicode(u"\x80\x90\xc2\x100")),
+ "\xc2\x80\xc2\x90\xc3\x82\x100")
+ eq(writer.encode(u"\x80\x90\xc2\x100"),
+ "\xc2\x80\xc2\x90\xc3\x82\x100")
+ eq(writer.encode(u"\xFF5E"), "\xc3\xbf5E")
+
+ eq(writer.encode('&"\'<>'), "&"'<>")
+ eq(writer.encode(unicode('&"\'<>')), "&"'<>")
+
+class SaveSessionTest(unittest.TestCase, support.FileTestMixin,
+ xmlsupport.ValidationTest):
+
+ dtd = "http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd"
+ thubanids = [((dtd, n), (None, "id")) for n in
+ ["fileshapesource", "filetable", "jointable",
+ "derivedshapesource", "dbshapesource", "dbconnection"]]
+ thubanidrefs = [((dtd, n), (None, m)) for n, m in
+ [("layer", "shapestore"),
+ ("jointable", "left"),
+ ("jointable", "right"),
+ ("derivedshapesource", "table"),
+ ("derivedshapesource", "shapesource"),
+ ("dbshapesource", "dbconn")]]
+ del n, m, dtd
+
+ def tearDown(self):
+ """Call self.session.Destroy
+
+ Test cases that create session should bind it to self.session so
+ that it gets destroyed properly
+ """
+ if hasattr(self, "session"):
+ self.session.Destroy()
+ self.session = None
+
+ def compare_xml(self, xml1, xml2):
+ list1 = xmlsupport.sax_eventlist(xml1, ids = self.thubanids,
+ idrefs = self.thubanidrefs)
+ list2 = xmlsupport.sax_eventlist(xml2, ids = self.thubanids,
+ idrefs = self.thubanidrefs)
+ if list1 != list2:
+ for a, b in zip(list1, list2):
+ if a != b:
+ self.fail("%r != %r" % (a, b))
+
+
+ def testEmptySession(self):
+ """Save an empty session"""
+ session = Session("empty session")
+ filename = self.temp_file_name("save_emptysession.thuban")
+ save_session(session, filename)
+ session.Destroy()
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ self.compare_xml(written_contents,
+ '<?xml version="1.0" encoding="UTF-8"?>\n'
+ '<!DOCTYPE session SYSTEM "thuban-1.1.dtd">\n'
+ '<session title="empty session" '
+ 'xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">'
+ '\n</session>\n')
+
+ self.validate_data(written_contents)
+
+ def testSingleLayer(self):
+ """Save a session with a single map with a single layer"""
+ # deliberately put an apersand in the title :)
+ session = Session("single map&layer")
+ proj = Projection(["proj=utm", "zone=27", "ellps=WGS84",
+ "datum=WGS84", "units=m"],
+ name = "WGS 84 / UTM zone 27N",
+ epsg = "32627")
+ map = Map("Test Map", projection = proj)
+ session.AddMap(map)
+ # use shapefile from the example data
+ shpfile = os.path.join(os.path.dirname(__file__),
+ os.pardir, "Data", "iceland", "political.shp")
+ layer = Layer("My Layer", session.OpenShapefile(shpfile))
+ map.AddLayer(layer)
+
+ filename = self.temp_file_name("save_singlemap.thuban")
+ save_session(session, filename)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="single map&layer"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <fileshapesource id="D1"
+ filename="../../Data/iceland/political.shp"
+ filetype="shapefile"/>
+ <map title="Test Map">
+ <projection epsg="32627" name="WGS 84 / UTM zone 27N">
+ <parameter value="proj=utm"/>
+ <parameter value="zone=27"/>
+ <parameter value="ellps=WGS84"/>
+ <parameter value="datum=WGS84"/>
+ <parameter value="units=m"/>
+ </projection>
+ <layer title="My Layer" shapestore="D1" visible="%s">
+ <classification>
+ <clnull label="">
+ <cldata fill="None" stroke="#000000"
+ stroke_width="1"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+ </session>'''
+
+ expected_contents = expected_template % "true"
+
+ self.compare_xml(written_contents, expected_contents)
+
+ self.validate_data(written_contents)
+
+ # Repeat with an invisible layer
+ layer.SetVisible(False)
+ save_session(session, filename)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = expected_template % "false"
+ self.compare_xml(written_contents, expected_contents)
+ self.validate_data(written_contents)
+
+ session.Destroy()
+
+ def testLayerProjection(self):
+ """Test saving layers with projections"""
+ # deliberately put an apersand in the title :)
+ session = self.session = Session("single map&layer")
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ map = Map("Test Map", projection = proj)
+ session.AddMap(map)
+ # use shapefile from the example data
+ shpfile = os.path.join(os.path.dirname(__file__),
+ os.pardir, "Data", "iceland", "political.shp")
+ layer = Layer("My Layer", session.OpenShapefile(shpfile))
+ proj = Projection(["proj=lcc", "ellps=clrk66",
+ "lat_1=0", "lat_2=20"],
+ "Layer Projection")
+ layer.SetProjection(proj)
+ map.AddLayer(layer)
+
+ filename = self.temp_file_name("save_layerproj.thuban")
+ save_session(session, filename)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="single map&layer"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <fileshapesource id="D1"
+ filename="../../Data/iceland/political.shp"
+ filetype="shapefile"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" shapestore="D1" visible="true">
+ <projection name="Layer Projection">
+ <parameter value="proj=lcc"/>
+ <parameter value="ellps=clrk66"/>
+ <parameter value="lat_1=0"/>
+ <parameter value="lat_2=20"/>
+ </projection>
+ <classification>
+ <clnull label="">
+ <cldata fill="None" stroke="#000000"
+ stroke_width="1"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+ </session>'''
+ #print written_contents
+ #print "********************************************"
+ #print expected_contents
+ self.compare_xml(written_contents, expected_contents)
+
+ self.validate_data(written_contents)
+
+ def testRasterLayer(self):
+
+ MASK_NONE = RasterLayer.MASK_NONE
+ MASK_BIT = RasterLayer.MASK_BIT
+ MASK_ALPHA = RasterLayer.MASK_ALPHA
+
+ for opacity, masktype, opname, maskname in \
+ [(1, MASK_BIT, '', ''),
+ (.2, MASK_BIT, 'opacity="0.2"', ''),
+ (1, MASK_ALPHA, '', 'masktype="alpha"'),
+ (.5, MASK_ALPHA, 'opacity="0.5"', 'masktype="alpha"'),
+ (1, MASK_NONE, '', 'masktype="none"'),
+ (0, MASK_NONE, 'opacity="0"', 'masktype="none"') ]:
+
+
+ # deliberately put an apersand in the title :)
+ session = Session("single map&layer")
+ map = Map("Test Map")
+ session.AddMap(map)
+ # use shapefile from the example data
+ imgfile = os.path.join(os.path.dirname(__file__),
+ os.pardir, "Data", "iceland", "island.tif")
+ layer = RasterLayer("My RasterLayer", imgfile)
+
+ layer.SetOpacity(opacity)
+ layer.SetMaskType(masktype)
+
+ map.AddLayer(layer)
+
+ filename = self.temp_file_name("%s.thuban" % self.id())
+ save_session(session, filename)
+ session.Destroy()
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="single map&layer"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <map title="Test Map">
+ <rasterlayer title="My RasterLayer"
+ filename="../../Data/iceland/island.tif"
+ visible="true" %s %s>
+ </rasterlayer>
+ </map>
+ </session>''' % (opname, maskname)
+ #print written_contents
+ #print "********************************************"
+ #print expected_contents
+ self.compare_xml(written_contents, expected_contents)
+
+ self.validate_data(written_contents)
+
+ def testClassifiedLayer(self):
+ """Save a session with a single map with classifications"""
+ # deliberately put an apersand in the title :)
+ session = Session("Map with Classifications")
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ map = Map("Test Map", projection = proj)
+ session.AddMap(map)
+ # use shapefile from the example data
+ shpfile = os.path.join(os.path.dirname(__file__),
+ os.pardir, "Data", "iceland", "political.shp")
+ layer = Layer("My Layer", session.OpenShapefile(shpfile))
+ map.AddLayer(layer)
+ layer2 = Layer("My Layer", layer.ShapeStore())
+ map.AddLayer(layer2)
+
+ clazz = layer.GetClassification()
+
+ layer.SetClassificationColumn("AREA")
+
+ clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
+ "single"))
+ clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
+ "single-text"))
+
+ clazz.AppendGroup(ClassGroupRange((0, 42),
+ ClassGroupProperties(),
+ "range"))
+
+ range = ClassGroupRange(Range("[0;42]"))
+ range.SetProperties(ClassGroupProperties())
+ range.SetLabel("new-range")
+ clazz.AppendGroup(range)
+
+
+ clazz = layer2.GetClassification()
+ layer2.SetClassificationColumn("POPYCOUN")
+
+ # Classification with Latin 1 text
+ clazz.AppendGroup(ClassGroupSingleton(
+ internal_from_unicode(u'\xe4\xf6\xfc'), # ae, oe, ue
+ ClassGroupProperties(),
+ internal_from_unicode(u'\xdcml\xe4uts'))) # Uemlaeuts
+
+ # Pattern
+ clazz.AppendGroup(ClassGroupPattern("BUI", ClassGroupProperties(),
+ "pattern"))
+
+ filename = self.temp_file_name("%s.thuban" % self.id())
+ save_session(session, filename)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="Map with Classifications"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <fileshapesource id="D1"
+ filename="../../Data/iceland/political.shp"
+ filetype="shapefile"/>
+ <map title="Test Map">
+ <projection name="Unknown">
+ <parameter value="zone=26"/>
+ <parameter value="proj=utm"/>
+ <parameter value="ellps=clrk66"/>
+ </projection>
+ <layer title="My Layer" shapestore="D1" visible="true">
+ <classification field="AREA" field_type="double">
+ <clnull label="">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clnull>
+ <clpoint value="42" label="single">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clpoint>
+ <clpoint value="text" label="single-text">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clpoint>
+ <clrange range="[0;42[" label="range">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clrange>
+ <clrange range="[0;42]" label="new-range">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clrange>
+ </classification>
+ </layer>
+ <layer title="My Layer" shapestore="D1" visible="true">
+ <classification field="POPYCOUN" field_type="string">
+ <clnull label="">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clnull>
+ <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
+ label="\xc3\x9cml\xc3\xa4uts">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clpoint>
+ <clpattern pattern="BUI" label="pattern">
+ <cldata fill="None" stroke="#000000" stroke_width="1"/>
+ </clpattern>
+ </classification>
+ </layer>
+ </map>
+ </session>'''
+
+ #print written_contents
+ #print "********************************************"
+ #print expected_contents
+ self.compare_xml(written_contents, expected_contents)
+
+ self.validate_data(written_contents)
+
+ session.Destroy()
+
+ def test_dbf_table(self):
+ """Test saving a session with a dbf table link"""
+ session = self.session = Session("a DBF Table session")
+ # use shapefile from the example data
+ dbffile = os.path.join(os.path.dirname(__file__),
+ os.pardir, "Data", "iceland", "political.dbf")
+ table = session.AddTable(DBFTable(dbffile))
+
+ filename = self.temp_file_name("save_singletable.thuban")
+ save_session(session, filename)
+
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="a DBF Table session"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <filetable id="D1" filename="../../Data/iceland/political.dbf"
+ filetype="DBF" title="political"/>
+ </session>'''
+
+ self.compare_xml(written_contents, expected_contents)
+ self.validate_data(written_contents)
+
+ def test_joined_table(self):
+ """Test saving a session with joined table"""
+ # Create a simple table to use in the join
+ dbffile = self.temp_file_name("save_joinedtable.dbf")
+ dbf = dbflib.create(dbffile)
+ dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
+ dbf.add_field("TEXT", dbflib.FTString, 10, 0)
+ dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
+ dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
+ dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
+ dbf.close()
+
+ # Create the session and a map
+ session = Session("A Joined Table session")
+ try:
+ map = Map("Test Map")
+ session.AddMap(map)
+
+ # Add the dbf file to the session
+ dbftable = session.AddTable(DBFTable(dbffile))
+
+ # Create a layer with the shapefile to use in the join
+ shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ os.pardir, "Data", "iceland",
+ "roads-line.shp")
+ layer = Layer("My Layer", session.OpenShapefile(shpfile))
+ map.AddLayer(layer)
+
+ # Do the join
+ store = layer.ShapeStore()
+ #for col in store.Table().Columns():
+ # print col.name
+ joined = TransientJoinedTable(session.TransientDB(),
+ store.Table(), "RDLNTYPE",
+ dbftable, "RDTYPE",
+ outer_join = True)
+ store = session.AddShapeStore(DerivedShapeStore(store, joined))
+ layer.SetShapeStore(store)
+
+ # Save the session
+ filename = self.temp_file_name("save_joinedtable.thuban")
+ save_session(session, filename)
+
+ # Read it back and compare
+ file = open(filename)
+ written_contents = file.read()
+ file.close()
+ expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="A Joined Table session"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <fileshapesource filename="../../Data/iceland/roads-line.shp"
+ filetype="shapefile" id="D142197204"/>
+ <filetable filename="save_joinedtable.dbf"
+ title="save_joinedtable"
+ filetype="DBF" id="D141881756"/>
+ <jointable id="D142180284"
+ title="Join of roads-line and save_joinedtable"
+ leftcolumn="RDLNTYPE" left="D142197204"
+ rightcolumn="RDTYPE" right="D141881756"
+ jointype="LEFT OUTER" />
+ <derivedshapesource id="D141915644"
+ table="D142180284"
+ shapesource="D142197204"/>
+ <map title="Test Map">
+ <layer title="My Layer"
+ shapestore="D141915644" visible="true">
+ <classification>
+ <clnull label="">
+ <cldata fill="None" stroke="#000000"
+ stroke_width="1"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+ </session>'''
+
+ self.compare_xml(written_contents, expected_contents)
+ self.validate_data(written_contents)
+ finally:
+ session.Destroy()
+ session = None
+
+
+ def test_save_postgis(self):
+ """Test saving a session with a postgis connection"""
+
+ class NonConnection(PostGISConnection):
+ """connection class that doesn't actually connect """
+ def connect(self):
+ pass
+
+ class NonConnectionStore(PostGISShapeStore):
+ """Shapestore that doesn't try to access the server"""
+ def _fetch_table_information(self):
+ # pretend that we've found a geometry column
+ self.geometry_column = "the_geom"
+ # pretend this is a ARC shape type.
+ self.shape_type = SHAPETYPE_ARC
+ def IDColumn(self):
+ """Return an object with a name attribute with value 'gid'"""
+ class dummycol:
+ name = "gid"
+ return dummycol
+
+ session = Session("A PostGIS Session")
+ try:
+ dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
+ user="grue")
+ session.AddDBConnection(dbconn)
+ map = Map("Test Map")
+ session.AddMap(map)
+ store = NonConnectionStore(dbconn, "roads")
+ session.AddShapeStore(store)
+ layer = Layer("Roads to Nowhere", store)
+ map.AddLayer(layer)
+
+ # Save the session
+ filename = self.temp_file_name(self.id() + ".thuban")
+ save_session(session, filename)
+
+ # Read it back and compare
+ file = open(filename)
+ written = file.read()
+ file.close()
+ expected = '''<?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
+ <session title="A PostGIS Session"
+ xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
+ <dbconnection id="DB"
+ dbtype="postgis" dbname="plugh"
+ host="xyzzy" port="42"
+ user="grue"/>
+ <dbshapesource id="roads" dbconn="DB" tablename="roads"
+ id_column="gid" geometry_column="the_geom"/>
+ <map title="Test Map">
+ <layer title="Roads to Nowhere"
+ shapestore="roads" visible="true">
+ <classification>
+ <clnull label="">
+ <cldata fill="None" stroke="#000000"
+ stroke_width="1"/>
+ </clnull>
+ </classification>
+ </layer>
+ </map>
+ </session>'''
+ self.compare_xml(written, expected)
+ self.validate_data(written)
+ finally:
+ session.Destroy()
+
+
+class MockDataStore:
+
+ """A very simple data store that only has dependencies"""
+
+ def __init__(self, name, *dependencies):
+ self.name = name
+ self.dependencies = dependencies
+
+ def __repr__(self):
+ return self.name
+
+ def Dependencies(self):
+ return self.dependencies
+
+
+class TestStoreSort(unittest.TestCase):
+
+ def check_sort(self, containers, sorted):
+ """Check whether the list of data containers is sorted"""
+ # check whether sorted is in the right order
+ seen = {}
+ for container in sorted:
+ self.failIf(id(container) in seen,
+ "Container %r at least twice in %r" % (container,
+ sorted))
+ for dep in container.Dependencies():
+ self.assert_(id(dep) in seen,
+ "Dependency %r of %r not yet seen" % (dep,
+ container))
+ seen[id(container)] = 1
+ # check whether all of containers is in sorted
+ for container in containers:
+ self.assert_(id(container) in seen,
+ "Container %r in containers but not in sorted")
+ self.assertEquals(len(containers), len(sorted))
+
+ def test_sort_data_stores(self):
+ """Test Thuban.Model.save.sort_data_stores"""
+ d1 = MockDataStore("d1")
+ d2 = MockDataStore("d2")
+ d3 = MockDataStore("d3", d1)
+ d4 = MockDataStore("d4", d1, d3)
+
+ containers = [d4, d1, d2, d3]
+ self.check_sort(containers, sort_data_stores(containers))
+ containers = [d1, d3, d2, d4]
+ self.check_sort(containers, sort_data_stores(containers))
+
+
+
+if __name__ == "__main__":
+ # Fake the __file__ global because it's needed by a test
+ import sys
+ __file__ = sys.argv[0]
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_scalebar.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_scalebar.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_scalebar.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,102 @@
+# Copyright (c) 2002 by Intevation GmbH
+# Authors:
+# Frank Koormann <frank.koormann at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Thuban scalebar calculations
+"""
+
+__version__ = "$Revision: 1674 $"
+# $Source$
+# $Id: test_scalebar.py 1674 2003-08-28 13:07:58Z bh $
+
+import unittest
+import os
+
+import support
+support.initthuban()
+
+from Thuban.Model.scalebar import deriveInterval, roundInterval
+
+class TestScalebar(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Test cases for the Thuban scalebar calculations
+ """
+
+ def test_deriveInterval(self):
+ """Test scalebar.deriveInterval()"""
+
+ # Zero savety
+ interval, unit = deriveInterval(100, 0.0)
+ self.assertEquals(interval, -1)
+ self.assertEquals(unit, '')
+
+ # meters
+ interval, unit = deriveInterval(100, 0.5)
+ self.assertEquals(interval, 200)
+ self.assertEquals(unit, 'm')
+
+ # kilometer conversion
+ interval, unit = deriveInterval(100, 0.05)
+ self.assertEquals(interval, 2)
+ self.assertEquals(unit, 'km')
+
+ def test_roundInterval(self):
+ """Test scalebar.roundInterval()"""
+
+ # 0.0005
+ interval, label = roundInterval(0.000545943795)
+ self.assertFloatEqual(interval, 0.0005)
+ self.assertEquals(label, '0.0005')
+
+ # 0.005
+ interval, label = roundInterval(0.00545943795)
+ self.assertFloatEqual(interval, 0.005)
+ self.assertEquals(label, '0.005')
+
+ # 0.05
+ interval, label = roundInterval(0.0545943795)
+ self.assertFloatEqual(interval, 0.05)
+ self.assertEquals(label, '0.05')
+
+ # 0.5
+ interval, label = roundInterval(0.545943795)
+ self.assertFloatEqual(interval, 0.5)
+ self.assertEquals(label, '0.5')
+
+ # 5
+ interval, label = roundInterval(5.45943795)
+ self.assertFloatEqual(interval, 5)
+ self.assertEquals(label, '5')
+
+ # 50
+ interval, label = roundInterval(54.5943795)
+ self.assertFloatEqual(interval, 50)
+ self.assertEquals(label, '50')
+
+ # 500
+ interval, label = roundInterval(545.943795)
+ self.assertFloatEqual(interval, 500)
+ self.assertEquals(label, '500')
+
+ # 5000
+ interval, label = roundInterval(5459.43795)
+ self.assertFloatEqual(interval, 5000)
+ self.assertEquals(label, '5000')
+
+ # 50000
+ interval, label = roundInterval(54594.3795)
+ self.assertFloatEqual(interval, 50000)
+ self.assertEquals(label, '50000')
+
+ # 500000
+ interval, label = roundInterval(545943.795)
+ self.assertFloatEqual(interval, -1)
+ self.assertEquals(label, '')
+
+if __name__ == "__main__":
+ unittest.main()
+
Added: packages/thuban/branches/upstream/current/test/test_selection.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_selection.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_selection.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,304 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""
+Test cases for Thuban.UI.selection
+"""
+
+__version__ = "$Revision: 723 $"
+# $Source$
+# $Id: test_selection.py 723 2003-04-24 15:31:53Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.session import Session
+from Thuban.Model.map import Map
+from Thuban.Model.layer import Layer
+from Thuban.UI.selection import Selection
+from Thuban.UI.messages import LAYER_SELECTED, SHAPES_SELECTED
+
+
+class TestSelection(unittest.TestCase, support.SubscriberMixin):
+
+ def setUp(self):
+ """Instantiate a selection.
+
+ Test cases implemented in this class can access the selection as
+ self.selection.
+
+ Also, subscribe self.subscribe_with_params to some of the
+ selection's messages.
+
+ Finally, create a list self.to_destroy with objects to be
+ destroyes by calling their destroy method in tearDown() for
+ objects created in test cases that need to be destroyed.
+ """
+ self.clear_messages()
+ self.selection = Selection()
+ for channel in (LAYER_SELECTED, SHAPES_SELECTED):
+ self.selection.Subscribe(channel, self.subscribe_with_params,
+ channel)
+ self.to_destroy = [self.selection]
+
+ def tearDown(self):
+ """Destroy all objects in self.to_destroy and clear the message list"""
+ for obj in self.to_destroy:
+ obj.Destroy()
+ self.to_destroy = None
+ self.session = None
+ self.selection = None
+ self.clear_messages()
+
+ def get_layer(self):
+ """Return a layer to have something to test with.
+
+ Also, instantiate self.session if not done already. The layer
+ (and the session when it is created) are added to
+ self.to_destroy so that they are properly destroyed at the end
+ of the test.
+
+ The layer should not be added to a map in the session to avoid a
+ situation where its destroy method is called twice. This
+ situation should not arise in the selection tests.
+ """
+ if not hasattr(self, "session"):
+ self.session = Session("Test Session for %s" % self.__class__)
+ self.to_destroy.append(self.session)
+ filename = os.path.join("..", "Data", "iceland", "roads-line.shp")
+ layer = Layer("Selection Test Layer",
+ self.session.OpenShapefile(filename))
+ self.to_destroy.append(layer)
+ return layer
+
+ def test_instatiation(self):
+ """Test initial state of the selection"""
+ self.assertEquals(self.selection.SelectedLayer(), None)
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ self.failIf(self.selection.HasSelectedLayer())
+
+ #
+ # SelectLayer Tests
+ #
+
+ def test_select_layer_without_current_selection(self):
+ """Test Selection.SelectLayer() without current selection"""
+ layer = self.get_layer()
+
+ self.selection.SelectLayer(layer)
+ # After selecting a layer, no shapes are selected
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # Since no shape was selected, only a LAYER_SELECTED message
+ # should have been issued.
+ self.check_messages([(layer, LAYER_SELECTED)])
+
+ def test_select_currently_selected_layer(self):
+ """Test Selection.SelectLayer(<currently selected layer>)"""
+ layer = self.get_layer()
+
+ self.selection.SelectLayer(layer)
+ self.clear_messages()
+ self.selection.SelectLayer(layer)
+
+ # After selecting a layer, no shapes are selected
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # Since nothing has changed, really, no messages should have
+ # been issued
+ self.check_messages([])
+
+ def test_select_layer_with_previous_selection(self):
+ """Test Selection.SelectLayer() with previous selection"""
+ self.selection.SelectShapes(self.get_layer(), [0])
+ self.clear_messages()
+
+ layer = self.get_layer()
+ self.selection.SelectLayer(layer)
+
+ # After selecting a layer, no shapes are selected
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # Since a shape and a layer was selected, a LAYER_SELECTED and a
+ # SHAPES_SELECTED message should have been issued.
+ self.check_messages([(layer, LAYER_SELECTED),
+ (layer, [], SHAPES_SELECTED)])
+
+ def test_select_layer_with_None(self):
+ """Test Selection.SelectLayer(None)
+
+ Calling SelectLayer with None should deselect it.
+ """
+ self.selection.SelectShapes(self.get_layer(), [0])
+ self.clear_messages()
+ self.selection.SelectLayer(None)
+
+ # After selecting a layer, no shapes are selected
+ self.assertEquals(self.selection.SelectedLayer(), None)
+ self.failIf(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # Since no shape was selected, only a LAYER_SELECTED message
+ # should have been issued.
+ self.check_messages([(None, LAYER_SELECTED),
+ (None, [], SHAPES_SELECTED)])
+
+ #
+ # SelectShapes Tests
+ #
+
+ def test_select_new_layer_and_new_shape(self):
+ """Test Selection.SelectShapes(<new layer>, <new shapes>)"""
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [0, 3, 1])
+
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [0, 1, 3])
+ self.check_messages([(layer, LAYER_SELECTED),
+ (layer, [0, 1, 3], SHAPES_SELECTED)])
+
+ def test_select_old_layer_and_old_shape(self):
+ """Test Selection.SelectShape(<old layer>, <old shapes>)"""
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [0, 10, 2])
+ self.clear_messages()
+ # Deliberate use a different order of the shape ids to check
+ # whether they're still considered equal
+ self.selection.SelectShapes(layer, [2, 0, 10])
+
+ # Selecting an already selected layer and shapes should not
+ # result in any messages but still have the right layer and
+ # shapes selected
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [0, 2, 10])
+ self.check_messages([])
+
+ def test_select_old_layer_and_new_shape(self):
+ """Test Selection.SelectShapes(<old layer>, <new shape>)"""
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [0])
+ self.clear_messages()
+ self.selection.SelectShapes(layer, [1])
+
+ # Selecting a different shape in the already selected layer
+ # should only produce a SHAPES_SELECTED message
+ # After selecting a shape, both a shape and a layer are selected
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [1])
+ self.check_messages([(layer, [1], SHAPES_SELECTED)])
+
+ #
+ # Adding Shapes Tests
+ #
+
+ def test_add_shapes_new_layer_new_shapes(self):
+ """Test Selection.SelectShapes(<same layer>, <new shapes>, add = 1)"""
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [10, 7], add = 1)
+
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ # The list of selected shapes will be sorted in ascending order
+ self.assertEquals(self.selection.SelectedShapes(), [7, 10])
+ self.check_messages([(layer, LAYER_SELECTED),
+ (layer, [7, 10], SHAPES_SELECTED)])
+
+ def test_add_shapes_same_layer_new_shapes(self):
+ """Test Selection.SelectShapes(<same layer>, <new shapes>, add = 1)"""
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [0, 6, 5])
+ self.clear_messages()
+
+ self.selection.SelectShapes(layer, [10, 7], add = 1)
+
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ # The list of selected shapes will be sorted in ascending order
+ self.assertEquals(self.selection.SelectedShapes(), [0, 5, 6, 7, 10])
+ self.check_messages([(layer, [0, 5, 6, 7, 10], SHAPES_SELECTED)])
+
+ def test_add_shapes_same_layer_already_selected_shapes(self):
+ """Test Selection.SelectShapes(<same layer>, <some old shapes>, add=1)
+ """
+ layer = self.get_layer()
+
+ self.selection.SelectShapes(layer, [0, 6, 5])
+ self.clear_messages()
+
+ self.selection.SelectShapes(layer, [6, 0], add = 1)
+
+ self.assertEquals(self.selection.SelectedLayer(), layer)
+ self.failUnless(self.selection.HasSelectedLayer())
+ # The list of selected shapes will be sorted in ascending order
+ self.assertEquals(self.selection.SelectedShapes(), [0, 5, 6])
+ self.check_messages([])
+
+ #
+ # ClearSelection Tests
+ #
+
+ def test_clear_selection(self):
+ """Test Selection.ClearSelection() when nothing is selected"""
+ self.selection.ClearSelection()
+
+ # After clearing the selection nothing is selected
+ self.assertEquals(self.selection.SelectedLayer(), None)
+ self.failIf(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # No messages should have been sent because the selection
+ # doesn't have changed due to the ClearSelection()
+ self.check_messages([])
+
+ def test_clear_selection_with_selected_layer(self):
+ """Test Selection.ClearSelection() when a layer is selected"""
+ self.selection.ClearSelection()
+
+ self.selection.SelectLayer(self.get_layer())
+ self.clear_messages()
+ self.selection.ClearSelection()
+
+ # After clearing the selection nothing is selected
+ self.assertEquals(self.selection.SelectedLayer(), None)
+ self.failIf(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # No messages should have been sent because the selection
+ # doesn't have changed due to the ClearSelection()
+ self.check_messages([(None, LAYER_SELECTED)])
+
+ def test_clear_selection_with_selected_shape(self):
+ """Test Selection.ClearSelection() when a layer is selected"""
+ self.selection.ClearSelection()
+
+ self.selection.SelectShapes(self.get_layer(), [0])
+ self.clear_messages()
+ self.selection.ClearSelection()
+
+ # After clearing the selection nothing is selected
+ self.assertEquals(self.selection.SelectedLayer(), None)
+ self.failIf(self.selection.HasSelectedLayer())
+ self.assertEquals(self.selection.SelectedShapes(), [])
+ # No messages should have been sent because the selection
+ # doesn't have changed due to the ClearSelection()
+ self.check_messages([(None, LAYER_SELECTED),
+ (None, [], SHAPES_SELECTED)])
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_session.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_session.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_session.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,412 @@
+# Copyright (c) 2002, 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Session class
+"""
+
+__version__ = "$Revision: 1676 $"
+# $Source$
+# $Id: test_session.py 1676 2003-08-28 13:14:44Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.messages import CHANGED, MAPS_CHANGED, FILENAME_CHANGED, \
+ MAP_PROJECTION_CHANGED, MAP_LAYERS_CHANGED, \
+ LAYER_VISIBILITY_CHANGED, LAYER_CHANGED, TABLE_REMOVED
+from Thuban.Model.session import Session
+from Thuban.Model.map import Map
+from Thuban.Model.layer import Layer
+from Thuban.Model.proj import Projection
+from Thuban.Model.color import Color
+from Thuban.Model.table import MemoryTable, FIELDTYPE_STRING, \
+ FIELDTYPE_INT, FIELDTYPE_DOUBLE
+from Thuban.Model.data import DerivedShapeStore
+from Thuban.Model.transientdb import TransientJoinedTable
+
+class TestSessionSimple(unittest.TestCase):
+
+ """Very simple test cases for Session"""
+
+ def setUp(self):
+ """Initialize self.session to None"""
+ self.session = None
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_initial_state(self):
+ """Test Session's initial state"""
+ session = self.session = Session("Test Session")
+ self.assertEquals(session.Title(), "Test Session")
+ self.assertEquals(session.Maps(), [])
+ self.assertEquals(session.Tables(), [])
+ self.assertEquals(session.ShapeStores(), [])
+ self.assertEquals(session.filename, None)
+ self.failIf(session.HasMaps())
+ self.failIf(session.WasModified())
+
+ def test_add_table(self):
+ """Test Session.AddTable()"""
+ session = self.session = Session("Test Session")
+ memtable = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", -1.5, 11),
+ ("RUINS", 0.0, 1),
+ ("FARM", 3.141, 2),
+ ("BUILDING", 2.5, 3),
+ ("HUT", 1e6, 4),
+ ("LIGHTHOUSE", -0.01, 5)])
+
+ # The session should be unmodified before the AddTable call and
+ # modified afterwards and of course the table should show up in
+ # Tables
+ self.failIf(session.WasModified())
+ table = session.AddTable(memtable)
+ self.assertEquals(session.Tables(), [table])
+ self.failUnless(session.WasModified())
+
+ def test_open_table_file(self):
+ """Test Session.OpenTableFile()"""
+ session = self.session = Session("Test Session")
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.dbf")
+ table = session.OpenTableFile(filename)
+ self.assertEquals(session.Tables(), [table])
+
+ def test_open_shapefile(self):
+ """Test Session.OpenShapefile()"""
+ session = self.session = Session("Test Session")
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ store = session.OpenShapefile(filename)
+ self.assertEquals(store.FileName(), os.path.abspath(filename))
+ # The filetype of a shapefile is "shapefile"
+ self.assertEquals(store.FileType(), "shapefile")
+ # The shapestore itself depends on nothing else
+ self.assertEquals(store.Dependencies(), ())
+ # The shapestore's table depends on the shapestore
+ self.assertEquals(store.Table().Dependencies(), (store,))
+
+ self.assertEquals(session.Tables(), [store.Table()])
+
+ def test_add_shapestore(self):
+ """Test Session.AddShapeStore()"""
+ session = self.session = Session("Test Session")
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ try:
+ store = session.OpenShapefile(filename)
+ derived = DerivedShapeStore(store, store.Table())
+ session.AddShapeStore(derived)
+ self.assertEquals(session.ShapeStores(), [store, derived])
+ finally:
+ store = derived = None
+
+
+ def test_unreferenced_tables(self):
+ """Test Session.UnreferencedTables()"""
+ session = self.session = Session("Test Session")
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ try:
+ store = session.OpenShapefile(filename)
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.dbf")
+ table = session.OpenTableFile(filename)
+ self.assertEquals(session.Tables(), [table, store.Table()])
+ # The store's table is reference by the store, so the only
+ # unreferenced table is the roads-line table
+ self.assertEquals(session.UnreferencedTables(), [table])
+ finally:
+ store = table = None
+
+
+class UnreferencedTablesTests(unittest.TestCase):
+
+ """Test cases for the session.UnreferencedTables() method"""
+
+ def setUp(self):
+ """Create a session with a few test tables"""
+ self.session = Session("Test Session")
+ memtable = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", -1.5, 11),
+ ("RUINS", 0.0, 1),
+ ("FARM", 3.141, 2),
+ ("BUILDING", 2.5, 3),
+ ("HUT", 1e6, 4),
+ ("LIGHTHOUSE", -0.01, 5)])
+ self.memtable = self.session.AddTable(memtable)
+ filename = os.path.join("..", "Data", "iceland",
+ "roads-line.dbf")
+ self.roads_line = self.session.OpenTableFile(filename)
+ filename = os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.dbf")
+ self.landmarks = self.session.OpenTableFile(filename)
+
+ def tearDown(self):
+ """Clear the session and layers"""
+ self.memtable = self.roads_line = self.landmarks = None
+ self.session.Destroy()
+ self.session = None
+
+ def test_unreferenced_tables(self):
+ """Test Session.UnreferencedTables()"""
+ self.assertEquals(self.session.UnreferencedTables(),
+ [self.memtable, self.roads_line, self.landmarks])
+
+ def test_unreferenced_tables_with_joins(self):
+ """Test Session.UnreferencedTables() with joins"""
+ joined = TransientJoinedTable(self.session.TransientDB(),
+ self.landmarks, "CLPTLABEL",
+ self.memtable, "type", outer_join = True)
+ try:
+ joined = self.session.AddTable(joined)
+ # After the join, landmarks and memtable are referenced by
+ # joined which in turn is referenced by nothing
+ self.assertEquals(self.session.UnreferencedTables(),
+ [self.roads_line, joined])
+ # Creating a DerivedShapeStore that references the joined table
+ # will remove it from the list of unreferenced tables,
+ store = self.session.OpenShapefile(
+ os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.dbf"))
+ derived = DerivedShapeStore(store, joined)
+ self.session.AddShapeStore(derived)
+ self.assertEquals(self.session.UnreferencedTables(),
+ [self.roads_line])
+ finally:
+ joined = derived = store = None
+
+class TestSessionBase(unittest.TestCase, support.SubscriberMixin):
+
+ """Base class for Session test cases that test the messages"""
+
+ def setUp(self):
+ """
+ Clear the message list, create a session and subscribe to its messages
+
+ Bind the session to self.session.
+ """
+ self.clear_messages()
+
+ # Create a Session and subscribe to all interesting channels.
+ self.session = Session("Test Session")
+ for channel in (CHANGED,
+ MAPS_CHANGED,
+ FILENAME_CHANGED,
+ MAP_PROJECTION_CHANGED,
+ MAP_LAYERS_CHANGED,
+ LAYER_VISIBILITY_CHANGED,
+ LAYER_CHANGED,
+ TABLE_REMOVED):
+ self.session.Subscribe(channel,
+ self.subscribe_with_params, channel)
+
+ def tearDown(self):
+ """Destroy self.session and clear the message list"""
+ self.session.Destroy()
+ self.session = None
+ self.clear_messages()
+
+
+class TestSessionMessages(TestSessionBase):
+
+ """Simple Session test cases that test messges"""
+
+ def test_add_map(self):
+ """Test Session.AddMap"""
+ self.failIf(self.session.WasModified())
+ map = Map("Some Map")
+ self.session.AddMap(map)
+ self.assert_(self.session.HasMaps())
+ self.assert_(self.session.WasModified())
+ self.assertEquals(self.session.Maps(), [map])
+ self.check_messages([(MAPS_CHANGED,),
+ (self.session, CHANGED)])
+
+ def test_set_filename(self):
+ """Test Session.SetFilename"""
+ self.session.SetFilename("session_set_filename_test")
+ self.session.filename = "session_set_filename_test"
+ self.check_messages([(FILENAME_CHANGED,),
+ (self.session, CHANGED)])
+
+ def test_remove_table(self):
+ """Test Session.RemoveTable()"""
+ memtable = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", -1.5, 11),
+ ("RUINS", 0.0, 1),
+ ("FARM", 3.141, 2),
+ ("BUILDING", 2.5, 3),
+ ("HUT", 1e6, 4),
+ ("LIGHTHOUSE", -0.01, 5)])
+ table = self.session.AddTable(memtable)
+ self.assertEquals(self.session.Tables(), [table])
+ self.clear_messages()
+ self.session.RemoveTable(table)
+ self.check_messages([(table, TABLE_REMOVED),
+ (self.session, CHANGED)])
+ self.assertEquals(self.session.Tables(), [])
+ self.assertRaises(ValueError, self.session.RemoveTable, table)
+
+
+class TestSessionWithContent(TestSessionBase):
+
+ """Session test cases that start with a filled session."""
+
+ def setUp(self):
+ """Extend the inherited method to add a non-empty map to self.session
+ """
+ TestSessionBase.setUp(self)
+ open_shp = self.session.OpenShapefile
+ self.arc_layer = Layer("Roads",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "roads-line.shp")))
+ self.poly_layer = Layer("Political",
+ open_shp(os.path.join("..", "Data", "iceland",
+ "political.shp")))
+ self.map = Map("A Map")
+ self.map.AddLayer(self.arc_layer)
+ self.map.AddLayer(self.poly_layer)
+ self.session.AddMap(self.map)
+ self.session.UnsetModified()
+ self.clear_messages()
+
+ def tearDown(self):
+ TestSessionBase.tearDown(self)
+ self.arc_layer = self.poly_layer = None
+
+ def test_remove_map(self):
+ """Test Session.RemoveMap"""
+ self.session.RemoveMap(self.map)
+ self.assert_(self.session.WasModified())
+ self.failIf(self.session.HasMaps())
+ self.check_messages([(MAPS_CHANGED,),
+ (self.session, CHANGED)])
+
+ def test_tree_info(self):
+ """Test Session.TreeInfo"""
+ self.assertEquals(self.session.TreeInfo(),
+ ('Session: Test Session',
+ ['Filename:',
+ 'Unmodified',
+ self.map]))
+
+ def test_forward_map_projection(self):
+ """Test Session forwarding of Map.SetProjection messages"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ self.check_messages([(self.map, MAP_PROJECTION_CHANGED),
+ (self.session, CHANGED)])
+ self.assert_(self.session.WasModified())
+
+ def test_forward_map_projection(self):
+ """Test Session forwarding of Map.SetProjection messages"""
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ self.assert_(self.session.WasModified())
+ self.check_messages([(self.map, None, MAP_PROJECTION_CHANGED),
+ (self.session, CHANGED)])
+
+ def test_forwarding_fill(self):
+ """Test Session's forwarding of Layer.SetFill messages"""
+ self.poly_layer.GetClassification().SetDefaultFill(Color(0.0, 0.5, 1.0))
+ self.assert_(self.session.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_CHANGED),
+ (self.session, CHANGED)])
+
+ def test_forwarding_stroke(self):
+ """Test Session's forwarding of Layer.SetStroke messages"""
+ self.poly_layer.GetClassification().\
+ SetDefaultLineColor(Color(0.0, 0.5, 1.0))
+ self.assert_(self.session.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_CHANGED),
+ (self.session, CHANGED)])
+
+ def test_forwarding_stroke_width(self):
+ """Test Session's forwarding of Layer.SetStrokeWidth messages"""
+ self.poly_layer.GetClassification().SetDefaultLineWidth(3)
+ self.assert_(self.session.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_CHANGED),
+ (self.session, CHANGED)])
+
+ def test_forwarding_visibility(self):
+ """Test Session's forwarding of Layer.SetVisible messages"""
+ self.poly_layer.SetVisible(0)
+ # Currently changing the visibility of a layer doesn't change
+ # the modification flag.
+ self.failIf(self.session.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_VISIBILITY_CHANGED),
+ (self.session, CHANGED)])
+
+ def test_unset_modified_map(self):
+ """Test Session.UnsetModified with map level changes"""
+ self.failIf(self.session.WasModified())
+ proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
+ self.map.SetProjection(proj)
+ self.assert_(self.session.WasModified())
+ self.session.UnsetModified()
+ self.failIf(self.session.WasModified())
+
+ def test_unset_modified_layer(self):
+ """Test Session.UnsetModified with layer level changes"""
+ self.failIf(self.session.WasModified())
+ self.poly_layer.GetClassification().SetDefaultLineWidth(3)
+ self.assert_(self.session.WasModified())
+ self.session.UnsetModified()
+ self.failIf(self.session.WasModified())
+ self.check_messages([(self.poly_layer, LAYER_CHANGED),
+ (self.session, CHANGED),
+ (CHANGED,)])
+
+ def test_shape_stores(self):
+ """Test Session.ShapeStores()"""
+ # Strictly speaking the session doesn't make guarantees about
+ # the order of the ShapeStores in the list, but currently it's
+ # deterministic and they're listed in the order in which they
+ # were created
+ self.assertEquals(self.session.ShapeStores(),
+ [self.arc_layer.ShapeStore(),
+ self.poly_layer.ShapeStore()])
+ # If we remove the map from the session and clear our instance
+ # variables that hold the layers and the map the list should
+ # become empty again.
+ self.session.RemoveMap(self.map)
+ self.arc_layer = self.poly_layer = self.map = None
+ self.assertEquals(self.session.ShapeStores(), [])
+
+ def test_tables(self):
+ """Test Session.Tables()"""
+ # Strictly speaking the session doesn't make guarantees about
+ # the order of the tables in the list, but currently it's
+ # deterministic and they're listed in the order in which they
+ # were opened
+ self.assertEquals(self.session.Tables(),
+ [self.arc_layer.ShapeStore().Table(),
+ self.poly_layer.ShapeStore().Table()])
+ # If we remove the map from the session and clear our instance
+ # variables that hold the layers and the map the list should
+ # become empty again.
+ self.session.RemoveMap(self.map)
+ self.arc_layer = self.poly_layer = self.map = None
+ self.assertEquals(self.session.Tables(), [])
+
+
+if __name__ == "__main__":
+ unittest.main()
Added: packages/thuban/branches/upstream/current/test/test_shapefilestore.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_shapefilestore.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_shapefilestore.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,220 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test cases for ShapefileStore"""
+
+__version__ = "$Revision: 1675 $"
+# $Source$
+# $Id: test_shapefilestore.py 1675 2003-08-28 13:09:48Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.data import ShapefileStore
+from Thuban.Model.session import Session
+from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
+from Thuban.Model.data import RAW_SHAPEFILE
+
+
+class TestShapefileStore(unittest.TestCase):
+
+ """Test cases for ShapefileStore"""
+
+ def setUp(self):
+ """Initialize self.session"""
+ self.session = Session("Test Session")
+ self.filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ self.store = ShapefileStore(self.session, self.filename)
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_accessors(self):
+ """Test ShapefileStore accessors"""
+ self.assertEquals(self.store.FileName(),
+ os.path.abspath(self.filename))
+
+ # The filetype of a shapefile is "shapefile"
+ self.assertEquals(self.store.FileType(), "shapefile")
+
+ def test_raw_format(self):
+ """Test ShapefileStore raw shape format"""
+ self.assertEquals(self.store.RawShapeFormat(), RAW_SHAPEFILE)
+
+ # For shapefiles the raw format means just the shape id as an
+ # int
+ self.assertEquals(self.store.Shape(5).RawData(), 5)
+
+ def test_dependencies(self):
+ """Test ShapefileStore and ShapeTable dependencies"""
+ # The shapestore itself depends on nothing else
+ self.assertEquals(self.store.Dependencies(), ())
+
+ # The shapestore's table depends on the shapestore
+ self.assertEquals(self.store.Table().Dependencies(), (self.store,))
+
+
+ def test_orig_shapestore(self):
+ """Test ShapefileStore.OrigShapeStore()"""
+ self.assertEquals(self.store.OrigShapeStore(), None)
+
+
+
+class ShapefileStoreTests(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Base class for the ShapefileStore tests"""
+
+
+class TestShapefileStoreArc(ShapefileStoreTests):
+
+ """Test cases for ShapefileStore with arc shapes"""
+
+ def setUp(self):
+ """Initialize self.session"""
+ self.session = Session("Test Session")
+ self.filename = os.path.join("..", "Data", "iceland",
+ "roads-line.shp")
+ self.store = ShapefileStore(self.session, self.filename)
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_shape_type(self):
+ """Test ShapefileStore.ShapeType() with arc shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_ARC)
+
+ def test_boundingbox(self):
+ """Test ShapefileStore.BoundingBox() with arc shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-24.450359344482422, 63.426830291748047,
+ -13.55668830871582, 66.520111083984375])
+
+ def test_num_shapes(self):
+ """Test ShapefileStore.NumShapes() with arc shapes"""
+ self.assertEquals(self.store.NumShapes(), 839)
+
+ def test_shapes_in_region(self):
+ """Test ShapefileStore.ShapesInRegion() with arc shapes"""
+ shapes = self.store.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
+ self.assertEquals([s.ShapeID() for s in shapes], [613, 726, 838])
+
+ def test_shape(self):
+ """Test ShapefileStore.Shape() with arc shapes"""
+ self.assertPointListEquals(self.store.Shape(32).Points(),
+ [[(-15.0821743011474, 66.2773818969726),
+ (-15.0263500213623, 66.2733917236328)]])
+
+ def test_shape_shapeid(self):
+ """Test ShapefileStore.Shape(i).ShapeID()"""
+ self.assertEquals(self.store.Shape(5).ShapeID(), 5)
+
+
+class TestShapefileStorePolygon(ShapefileStoreTests):
+
+ """Test cases for ShapefileStore with plygon shapes"""
+
+ def setUp(self):
+ """Initialize self.session"""
+ self.session = Session("Test Session")
+ """Test ShapeStore with polygon shapes"""
+ self.filename = os.path.join("..", "Data", "iceland",
+ "political.shp")
+ self.store = ShapefileStore(self.session, self.filename)
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_shape_type(self):
+ """Test ShapeStore.ShapeType() with polygon shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_POLYGON)
+
+ def test_boundingbox(self):
+ """Test ShapefileStore.BoundingBox() with polygon shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-24.546524047851562, 63.286754608154297,
+ -13.495815277099609, 66.563774108886719])
+
+ def test_num_shapes(self):
+ """Test ShapefileStore.NumShapes() with polygon shapes"""
+ self.assertEquals(self.store.NumShapes(), 156)
+
+ def test_shapes_in_region(self):
+ """Test ShapefileStore.ShapesInRegion() with polygon shapes"""
+ shapes = self.store.ShapesInRegion((-24.0, 64.0, -23.9, 64.1))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [91, 92, 144, 146, 148, 150, 152, 153])
+
+ def test_shape(self):
+ """Test ShapefileStore.Shape() with polygon shapes"""
+ self.assertPointListEquals(self.store.Shape(4).Points(),
+ [[(-22.40639114379882, 64.714111328125),
+ (-22.41621208190918, 64.716003417968),
+ (-22.40605163574218, 64.719200134277),
+ (-22.40639114379882, 64.714111328125)]])
+
+class TestShapefileStorePoint(ShapefileStoreTests):
+
+ """Test cases for ShapefileStore with plygon shapes"""
+
+ def setUp(self):
+ """Initialize self.session"""
+ self.session = Session("Test Session")
+ """Test ShapeStore with point shapes"""
+ self.filename = os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.shp")
+ self.store = ShapefileStore(self.session, self.filename)
+
+ def tearDown(self):
+ """Call self.session.Destroy() and reset self.session to None"""
+ self.session.Destroy()
+ self.session = None
+
+ def test_shape_type(self):
+ """Test ShapeStore.ShapeType() with point shapes"""
+ self.assertEquals(self.store.ShapeType(), SHAPETYPE_POINT)
+
+ def test_boundingbox(self):
+ """Test ShapefileStore.BoundingBox() with point shapes"""
+ self.assertFloatSeqEqual(self.store.BoundingBox(),
+ [-23.806047439575195, 63.405960083007812,
+ -15.12291431427002, 66.36572265625])
+
+ def test_num_shapes(self):
+ """Test ShapefileStore.NumShapes() with point shapes"""
+ self.assertEquals(self.store.NumShapes(), 34)
+
+ def test_shapes_in_region(self):
+ """Test ShapefileStore.ShapesInRegion() with point shapes"""
+ shapes = self.store.ShapesInRegion((-24.0, 64.0, -23.80, 64.1))
+ self.assertEquals([s.ShapeID() for s in shapes],
+ [0, 1, 2, 3, 4, 5, 27, 28, 29, 30, 31])
+
+ def test_all_shapes(self):
+ """Test ShapefileStore.AllShapes()"""
+ # This test is probably not needed for other shape types as it's
+ # not specific to the type or the data at all.
+ self.assertEquals([s.ShapeID() for s in self.store.AllShapes()],
+ range(self.store.NumShapes()))
+
+ def test_shape(self):
+ """Test ShapefileStore.Shape() with point shapes"""
+ self.assertPointListEquals(self.store.Shape(0).Points(),
+ [[(-22.711074829101562, 66.36572265625)]])
+
+if __name__ == "__main__":
+ support.run_tests()
+
Added: packages/thuban/branches/upstream/current/test/test_stringrepresentation.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_stringrepresentation.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_stringrepresentation.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,40 @@
+# Copyright (c) 2005 by Intevation GmbH
+# Authors:
+# Bernhard Reiter <bernhard at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the functions for Thuban's string representation.
+"""
+
+__version__ = "$Revision: 2673 $"
+# $Source$
+# $Id: test_stringrepresentation.py 2673 2005-10-19 08:08:29Z bernhard $
+
+import unittest
+
+import support
+support.initthuban()
+
+import Thuban
+
+class TestInternalEncoding(unittest.TestCase):
+ """Test around the thuban default encoding."""
+
+ def setUp(self):
+ """Save the old internal encoding, so we can restore it."""
+ self.saved_encoding=Thuban.get_internal_encoding()
+
+ def tearDown(self):
+ """Restore saved internal encoding."""
+ Thuban.set_internal_encoding(self.saved_encoding)
+
+ def test_notice_bad_internalencoding(self):
+ bad_encoding="this-never-is-a-valid-encoding"
+ self.assertRaises(LookupError,
+ Thuban.set_internal_encoding,bad_encoding)
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_transientdb.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_transientdb.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_transientdb.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,415 @@
+# Copyright (c) 2002, 2003, 2006 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the Transient DB classes
+"""
+
+__version__ = "$Revision: 2705 $"
+# $Source$
+# $Id: test_transientdb.py 2705 2006-09-24 18:55:30Z bernhard $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import dbflib
+from Thuban.Model.table import DBFTable, MemoryTable, FIELDTYPE_STRING, \
+ FIELDTYPE_INT, FIELDTYPE_DOUBLE, table_to_dbf
+from Thuban.Model.transientdb import TransientDatabase, TransientTable, \
+ TransientJoinedTable, AutoTransientTable
+
+
+class TestTransientTable(unittest.TestCase, support.FileTestMixin):
+
+ def setUp(self):
+ """Create a transient database as self.transientdb"""
+ filename = self.temp_file_name("transient_table.sqlite")
+ if os.path.exists(filename):
+ os.remove(filename)
+ journal = filename + "-journal"
+ if os.path.exists(journal):
+ print "removing journal", journal
+ os.remove(journal)
+ self.transientdb = TransientDatabase(filename)
+
+ def tearDown(self):
+ self.transientdb.close()
+
+ def run_iceland_political_tests(self, table):
+ """Run some tests on table
+
+ Assume that table holds the data of the file
+ ../Data/iceland/political.dbf sample file.
+ """
+ self.assertEquals(table.NumRows(), 156)
+ self.assertEquals(table.NumColumns(), 8)
+
+ # Check one each of the possible field types.
+ columns = table.Columns()
+ self.assertEquals(columns[0].name, 'AREA')
+ self.assertEquals(columns[0].type, FIELDTYPE_DOUBLE)
+ self.assertEquals(columns[3].name, 'PONET_ID')
+ self.assertEquals(columns[3].type, FIELDTYPE_INT)
+ self.assertEquals(columns[6].name, 'POPYCOUN')
+ self.assertEquals(columns[6].type, FIELDTYPE_STRING)
+
+ # HasColumn
+ self.failUnless(table.HasColumn("AREA"))
+ self.failUnless(table.HasColumn(1))
+ # HasColumn for non-exisiting columns
+ self.failIf(table.HasColumn("non_existing_name"))
+ self.failIf(table.HasColumn(100))
+
+ # Reading rows and values.
+ self.assertEquals(table.ReadRowAsDict(144),
+ {'POPYCOUN': 'IC', 'POPYADMIN': '', 'PONET_': 146,
+ 'AREA': 19.462,
+ 'POPYTYPE': 1, 'PERIMETER': 88.518000000000001,
+ 'POPYREG': '1',
+ 'PONET_ID': 145})
+ self.assertEquals(table.ReadRowAsDict(144, row_is_ordinal = 1),
+ {'POPYCOUN': 'IC', 'POPYADMIN': '', 'PONET_': 146,
+ 'AREA': 19.462,
+ 'POPYTYPE': 1, 'PERIMETER': 88.518000000000001,
+ 'POPYREG': '1',
+ 'PONET_ID': 145})
+ self.assertEquals(table.ReadValue(144, "AREA"), 19.462)
+ self.assertEquals(table.ReadValue(144, 3), 145)
+ self.assertEquals(table.ReadValue(144, "AREA", row_is_ordinal = 1),
+ 19.462)
+ self.assertEquals(table.ReadValue(144, 3, row_is_ordinal = 1), 145)
+
+ self.assertEquals(table.RowIdToOrdinal(23), 23)
+ self.assertEquals(table.RowOrdinalToId(23), 23)
+
+ # ValueRange may induce a copy to the transient database.
+ # Therefore we put it last so that we can execute this method
+ # twice to check whether the other methods still work after the
+ # copy
+ self.assertEquals(table.ValueRange("AREA"), (0.0, 19.462))
+
+ unique = table.UniqueValues("PONET_ID")
+ unique.sort()
+ self.assertEquals(unique, range(1, 157))
+
+ def test_transient_table(self):
+ """Test TransientTable(dbftable)
+
+ The TransientTable should copy the data to the
+ TransientDatabase.
+ """
+ orig_table = DBFTable(os.path.join("..", "Data", "iceland",
+ "political.dbf"))
+ table = TransientTable(self.transientdb, orig_table)
+ self.run_iceland_political_tests(table)
+
+ # The transient_table method should return the table itself
+ self.assert_(table is table.transient_table())
+
+ # The title is simply copied over from the original table
+ self.assertEquals(table.Title(), orig_table.Title())
+
+ # The TransientTable class itself doesn't implement the
+ # Dependencies method, so we don't test it.
+
+
+ def test_auto_transient_table(self):
+ """Test AutoTransientTable(dbftable)
+
+ The AutoTransientTable should copy the data to the
+ TransientDatabase on demand.
+ """
+ orig_table = DBFTable(os.path.join("..", "Data", "iceland",
+ "political.dbf"))
+ table = AutoTransientTable(self.transientdb, orig_table)
+
+ # Run the tests twice so that we execute them once when the data
+ # has not been copied to the transient db yet and once when it
+ # has. This assumes that run_iceland_political_tests does at
+ # least one call to a method that copies to the transient db at
+ # its end.
+ self.run_iceland_political_tests(table)
+ # At this point the data has probably not been copied to the
+ # transient DB yet, so we force it by calling the
+ # transient_table method.
+ table.transient_table()
+
+ # Run the tests again.
+ self.run_iceland_political_tests(table)
+
+ def test_auto_transient_table_query(self):
+ """Test AutoTransientTable.SimpleQuery()"""
+ orig_table = DBFTable(os.path.join("..", "Data", "iceland",
+ "political.dbf"))
+ table = AutoTransientTable(self.transientdb, orig_table)
+ # Only a simple test here. The AutoTransientTable simply
+ # delegates to its transient table so it should be OK that the
+ # real test for it is in test_transient_table_query. However,
+ # it's important to check that the column handling works
+ # correctly because the AutoTransientTable and it's underlying
+ # transient table use different column object types.
+ self.assertEquals(table.SimpleQuery(table.Column("AREA"), ">", 10.0),
+ [144])
+
+ # test using a Column object as the right parameter
+ self.assertEquals(table.SimpleQuery(table.Column("POPYTYPE"),
+ "==",
+ table.Column("POPYREG")),
+ range(156))
+
+ def test_auto_transient_table_dependencies(self):
+ """Test AutoTransientTable.Dependencies()"""
+ orig_table = DBFTable(os.path.join("..", "Data", "iceland",
+ "political.dbf"))
+ table = AutoTransientTable(self.transientdb, orig_table)
+ self.assertEquals(table.Dependencies(), (orig_table,))
+
+ def test_auto_transient_table_title(self):
+ """Test AutoTransientTable.Title()"""
+ orig_table = DBFTable(os.path.join("..", "Data", "iceland",
+ "political.dbf"))
+ table = AutoTransientTable(self.transientdb, orig_table)
+ # The title is of course the same as that of the original table
+ self.assertEquals(table.Title(), orig_table.Title())
+
+ def test_transient_joined_table(self):
+ """Test TransientJoinedTable"""
+ simple = MemoryTable([("type", FIELDTYPE_STRING),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", 0),
+ ("RUINS", 1),
+ ("FARM", 2),
+ ("BUILDING", 3),
+ ("HUT", 4),
+ ("LIGHTHOUSE", 5)])
+ auto = AutoTransientTable(self.transientdb, simple)
+ filename = os.path.join("..", "Data", "iceland",
+ "cultural_landmark-point.dbf")
+ landmarks = AutoTransientTable(self.transientdb, DBFTable(filename))
+
+ table = TransientJoinedTable(self.transientdb, landmarks, "CLPTLABEL",
+ auto, "type")
+
+ self.assertEquals(table.NumRows(), 34)
+ self.assertEquals(table.NumColumns(), 8)
+ self.assertEquals(table.Column(0).type, FIELDTYPE_DOUBLE)
+ self.assertEquals(table.Column(0).name, 'AREA')
+ self.assertEquals(table.Column(7).type, FIELDTYPE_INT)
+ self.assertEquals(table.Column(7).name, 'code')
+ self.assertEquals(table.Column(4).type, FIELDTYPE_STRING)
+ self.assertEquals(table.Column(4).name, 'CLPTLABEL')
+ # HasColumn
+ self.failUnless(table.HasColumn("AREA"))
+ self.failUnless(table.HasColumn(1))
+ # HasColumn for non-exisiting columns
+ self.failIf(table.HasColumn("non_existing_name"))
+ self.failIf(table.HasColumn(100))
+
+ # Reading rows and values
+ self.assertEquals(table.ReadRowAsDict(22),
+ {'PERIMETER': 0.0, 'CLPOINT_': 23,
+ 'AREA': 0.0, 'CLPTLABEL': 'RUINS',
+ 'CLPOINT_ID': 38, 'CLPTFLAG': 0,
+ 'code': 1, 'type': 'RUINS'})
+ self.assertEquals(table.ReadValue(22, "type"), 'RUINS')
+ self.assertEquals(table.ReadValue(22, 7), 1)
+ self.assertEquals(table.ReadValue(22, "type", row_is_ordinal = 1),
+ "RUINS")
+ self.assertEquals(table.ReadValue(22, 7, row_is_ordinal = 1), 1)
+ self.assertEquals(table.RowIdToOrdinal(23), 23)
+ self.assertEquals(table.RowOrdinalToId(23), 23)
+
+ # The transient_table method should return the table itself
+ self.assert_(table is table.transient_table())
+
+ # The TransientJoinedTable depends on both input tables
+ self.assertEquals(table.Dependencies(), (landmarks, auto))
+
+ # The title is constructed from the titles of the input tables.
+ self.assertEquals(table.Title(),
+ "Join of %s and %s" % (landmarks.Title(),
+ auto.Title()))
+
+
+ def test_transient_joined_table_same_column_name(self):
+ """Test TransientJoinedTable join on columns with same name
+
+ The transient DB maps the column names used by the tables to
+ another set of names used only inside the SQLite database. There
+ was a bug in the way this mapping was used when joining on
+ fields with the same names in both tables so that the joined
+ table ended up joining on the same column in the same table.
+ """
+ mem_stretches = MemoryTable([("stretch_id", FIELDTYPE_INT)],
+ [(i,) for i in range(4)])
+ stretches = AutoTransientTable(self.transientdb, mem_stretches)
+
+ mem_discharges = MemoryTable([("disch_id", FIELDTYPE_INT),
+ ("stretch_id", FIELDTYPE_INT)],
+ [(1, 0), (2, 3)])
+ discharges = AutoTransientTable(self.transientdb, mem_discharges)
+
+ table = TransientJoinedTable(self.transientdb, stretches, "stretch_id",
+ discharges, "stretch_id",
+ outer_join = True)
+
+ self.assertEquals(table.NumRows(), 4)
+ self.assertEquals(table.NumColumns(), 3)
+
+ # HasColumn
+ self.failUnless(table.HasColumn("stretch_id"))
+ self.failUnless(table.HasColumn("disch_id"))
+
+
+ def test_transient_joined_table_with_equal_column_names(self):
+ """Test TransientJoinedTable join on tables with equal column names
+
+ If a name collision occurs for the field names, underscores are
+ appended as long as any collision is resolved.
+ """
+ mem_stretches = MemoryTable([("stretch_id", FIELDTYPE_INT),
+ ("name", FIELDTYPE_INT)],
+ [(0, 10), (1, 11), (2, 12), (3, 13) ])
+ stretches = AutoTransientTable(self.transientdb, mem_stretches)
+
+ mem_discharges = MemoryTable([("disch_id", FIELDTYPE_INT),
+ ("stretch_id", FIELDTYPE_INT),
+ ("name", FIELDTYPE_INT)],
+ [(1, 0, 1), (2, 3, 2)])
+ discharges = AutoTransientTable(self.transientdb, mem_discharges)
+
+ table = TransientJoinedTable(self.transientdb, stretches, "stretch_id",
+ discharges, "stretch_id",
+ outer_join = True)
+
+ self.assertEquals(table.NumRows(), 4)
+ self.assertEquals(table.NumColumns(), 5)
+
+ # HasColumn
+ self.assertEquals([c.name for c in table.Columns()],
+ ["stretch_id", "name", "disch_id", "stretch_id_",
+ "name_"])
+
+ def test_transient_joined_table_name_collisions_dont_modify_in_place(self):
+ """Test TransientJoinedTable name-collisions do not modifying in place
+
+ The name collision work-around by appending underscores
+ accidentally modified the column objects in place. We do two
+ joins therefore in reverse order to detect this: The first join
+ will lead to a modified name in the column object of the right
+ table which is then used as the left table in the second join so
+ the underscored name will appear before the non-underscored one
+ in the list of column names after the second join.
+ """
+ mem1 = MemoryTable([("stretch_id", FIELDTYPE_INT),
+ ("name", FIELDTYPE_INT)],
+ [(0, 10), (1, 11), (2, 12), (3, 13) ])
+ table1 = AutoTransientTable(self.transientdb, mem1)
+
+ mem2 = MemoryTable([("stretch_id", FIELDTYPE_INT),
+ ("name", FIELDTYPE_INT)],
+ [(0, 10), (1, 11), (2, 12), (3, 13) ])
+ table2 = AutoTransientTable(self.transientdb, mem2)
+
+ table = TransientJoinedTable(self.transientdb, table1, "stretch_id",
+ table2, "stretch_id", outer_join = True)
+ table = TransientJoinedTable(self.transientdb, table2, "stretch_id",
+ table1, "stretch_id", outer_join = True)
+
+ self.assertEquals([c.name for c in table.Columns()],
+ ["stretch_id", "name", "stretch_id_", "name_"])
+
+ def test_transient_table_read_twice(self):
+ """Test TransientTable.ReadRowAsDict() reading the same record twice"""
+ simple = MemoryTable([("type", FIELDTYPE_STRING),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", 0),
+ ("RUINS", 1),
+ ("FARM", 2),
+ ("BUILDING", 3),
+ ("HUT", 4),
+ ("LIGHTHOUSE", 5)])
+ table = TransientTable(self.transientdb, simple)
+
+ # There was a bug where reading the same record twice would
+ # raise an exception in the second call because of an
+ # unitialized local variable, so for passing the test it's
+ # enough if reading simply succeeds. OTOH, while we're at it we
+ # might as well check whether the results are equal anyway :)
+ result1 = table.ReadRowAsDict(3)
+ result2 = table.ReadRowAsDict(3)
+ self.assertEquals(result1, result2)
+
+
+ def test_transient_table_query(self):
+ """Test TransientTable.SimpleQuery()"""
+ simple = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("OTHER/UNKNOWN", -1.5, 11),
+ ("RUINS", 0.0, 1),
+ ("FARM", 3.141, 2),
+ ("BUILDING", 2.5, 3),
+ ("HUT", 1e6, 4),
+ ("LIGHTHOUSE", -0.01, 5)])
+ table = TransientTable(self.transientdb, simple)
+
+ # A column and a value
+ self.assertEquals(table.SimpleQuery(table.Column(0), "==", "RUINS"),
+ [1])
+ self.assertEquals(table.SimpleQuery(table.Column(2), "!=", 2),
+ [0, 1, 3, 4, 5])
+ self.assertEquals(table.SimpleQuery(table.Column(1), "<", 1.0),
+ [0, 1, 5])
+ self.assertEquals(table.SimpleQuery(table.Column(1), "<=", -1.5),
+ [0])
+ self.assertEquals(table.SimpleQuery(table.Column(2), ">", 3),
+ [0, 4, 5])
+ self.assertEquals(table.SimpleQuery(table.Column(2), ">=", 3),
+ [0, 3, 4, 5])
+
+ # Two columns as operands
+ self.assertEquals(table.SimpleQuery(table.Column(1),
+ "<=", table.Column(2)),
+ [0, 1, 3, 5])
+
+ # Test whether invalid operators raise a ValueError
+ self.assertRaises(ValueError,
+ table.SimpleQuery,
+ table.Column(1), "<<", table.Column(2))
+
+ def test_transienttable_to_dbf(self):
+ memtable = MemoryTable([("type", FIELDTYPE_STRING),
+ ("value", FIELDTYPE_DOUBLE),
+ ("code", FIELDTYPE_INT)],
+ [("UNKNOWN", 0.0, 0),
+ ("Foo", 0.5, -1),
+ ("Foo", 1.0/256, 100),
+ ("bar", 1e10, 17)])
+ table = TransientTable(self.transientdb, memtable)
+ filename = self.temp_file_name("test_transienttable_to_dbf.dbf")
+ table_to_dbf(table, filename)
+
+ dbf = dbflib.DBFFile(filename)
+ self.assertEquals(dbf.read_record(2),
+ {'code': 100, 'type': 'Foo', 'value': 0.00390625})
+ self.assertEquals(dbf.field_count(), 3)
+ self.assertEquals(dbf.record_count(), 4)
+ self.assertEquals(dbf.field_info(0),
+ (dbflib.FTString, "type", 7, 0))
+ self.assertEquals(dbf.field_info(1),
+ (dbflib.FTDouble, "value", 24, 12))
+ self.assertEquals(dbf.field_info(2),
+ (dbflib.FTInteger, "code", 3, 0))
+
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_viewport.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_viewport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_viewport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,509 @@
+# Copyright (c) 2003, 2004 by Intevation GmbH
+# Authors:
+# Jonathan Coles <jonathan at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+"""
+Test the interaction with the view
+"""
+
+__version__ = "$Revision: 2297 $"
+# $Source$
+# $Id: test_viewport.py 2297 2004-07-22 13:07:52Z bh $
+
+import os
+import unittest
+
+import postgissupport
+import support
+support.initthuban()
+
+from Thuban.UI.viewport import ViewPort, ZoomInTool, ZoomOutTool, \
+ PanTool, IdentifyTool, LabelTool
+
+from Thuban.Model.map import Map
+from Thuban.Model.proj import Projection
+from Thuban.Model.layer import Layer
+from Thuban.Model.session import Session
+from Thuban.Model.color import Color
+from Thuban.Model.postgisdb import PostGISConnection
+from Thuban.UI.messages import SCALE_CHANGED, MAP_REPLACED
+from Thuban.Model.messages import TITLE_CHANGED
+
+class Event:
+ pass
+
+
+class MockView(ViewPort):
+
+ def GetTextExtent(self, text):
+ """Mock implementation so that the test cases work"""
+ # arbitrary numbers, really just so the tests pass
+ return 40, 20
+
+
+
+class SimpleViewPortTest(unittest.TestCase):
+
+ """Simple ViewPort tests"""
+
+ def test_default_size(self):
+ """Test ViewPort default size and scale"""
+ port = ViewPort()
+ try:
+ self.assertEquals(port.GetPortSizeTuple(), (400, 300))
+ self.assertEquals(port.scale, 1.0)
+ self.assertEquals(port.offset, (0, 0))
+ self.assertEquals(port.VisibleExtent(), (0.0, -300.0, 400.0, 0.0))
+ finally:
+ port.Destroy()
+
+ def test_init_with_size(self):
+ """Test ViewPort(<size>)"""
+ port = ViewPort((1001, 1001))
+ try:
+ self.assertEquals(port.GetPortSizeTuple(), (1001, 1001))
+ self.assertEquals(port.VisibleExtent(), (0.0, -1001.0, 1001.0, 0.0))
+ finally:
+ port.Destroy()
+
+ def test_visible_extent(self):
+ """Test ViewPort.VisibleExtent()"""
+ class MockMap:
+ def ProjectedBoundingBox(self):
+ return (500, 400, 600, 500)
+ # noops that the viewport expects but which aren't needed
+ # here:
+ Subscribe = Unsubscribe = lambda *args: None
+
+ map = MockMap()
+ port = ViewPort((1000, 1000))
+ try:
+ port.SetMap(map)
+ # The viewport adjusts automatically to the map. Since both
+ # the map's bounding box and the viewport are square the map
+ # fits exactly.
+ self.assertEquals(port.VisibleExtent(), (500, 400, 600, 500))
+
+ # Zoom in a bit
+ port.ZoomFactor(2)
+ self.assertEquals(port.VisibleExtent(), (525, 425, 575, 475))
+ finally:
+ port.Destroy()
+
+
+class ViewPortTest(unittest.TestCase, support.SubscriberMixin,
+ support.FloatComparisonMixin):
+
+ def build_path(self, filename):
+ return os.path.join("..", "Data", "iceland", filename)
+
+ def open_shapefile(self, filename):
+ """Open and return a shapestore for filename in the iceland data set"""
+ return self.session.OpenShapefile(self.build_path(filename))
+
+ def setUp(self):
+ self.session = Session("Test session for %s" % self.__class__)
+
+ # make view port 1001x1001 so we have an exact center
+ self.port = MockView((1001, 1001))
+
+ proj = Projection(["proj=latlong",
+ "to_meter=.017453292519943",
+ "ellps=clrk66"])
+
+ self.map = map = Map("title", proj)
+ layer = Layer("Polygon", self.open_shapefile("political.shp"))
+ layer.GetClassification().GetDefaultGroup()\
+ .GetProperties().SetFill(Color(0,0,0))
+ map.AddLayer(layer)
+ layer = Layer("Point",
+ self.open_shapefile("cultural_landmark-point.shp"))
+ layer.GetClassification().GetDefaultGroup()\
+ .GetProperties().SetFill(Color(0,0,0))
+ map.AddLayer(layer)
+ layer = Layer("Arc", self.open_shapefile("roads-line.shp"))
+ layer.GetClassification().GetDefaultGroup()\
+ .GetProperties().SetFill(Color(0,0,0))
+ map.AddLayer(layer)
+ self.session.AddMap(map)
+
+ self.layer = layer
+
+ self.port.SetMap(map)
+ for msg in (SCALE_CHANGED, MAP_REPLACED, TITLE_CHANGED):
+ self.port.Subscribe(msg, self.subscribe_with_params, msg)
+ self.clear_messages()
+
+ def tearDown(self):
+ self.port.Destroy()
+ self.session.Destroy()
+ self.map = self.session = self.port = self.layer = None
+
+ def test_inital_settings(self):
+ self.failIf(self.port.HasSelectedLayer())
+ self.failIf(self.port.HasSelectedShapes())
+
+ def test_win_to_proj(self):
+ self.assertFloatSeqEqual(self.port.win_to_proj(0, 0),
+ (-24.546524047851978, 70.450618743897664))
+ self.assertFloatSeqEqual(self.port.win_to_proj(100, 0),
+ (-23.442557137686929, 70.450618743897664))
+ self.assertFloatSeqEqual(self.port.win_to_proj(0, 100),
+ (-24.546524047851978, 69.346651833732622))
+
+ def test_proj_to_win(self):
+ self.assertFloatSeqEqual(self.port.proj_to_win(-24.546524047851978,
+ 70.450618743897664),
+ (0, 0))
+ self.assertFloatSeqEqual(self.port.proj_to_win(-23.442557137686929,
+ 70.450618743897664),
+ (100, 0))
+ self.assertFloatSeqEqual(self.port.proj_to_win(-24.546524047851978,
+ 69.346651833732622),
+ (0, 100))
+
+ def test_set_map(self):
+ """Test ViewPort.SetMap()"""
+ # The port already has a map. So we set it to None before we set
+ # it to self.map again.
+
+ # Setting the map to None does not change the scale, but it will
+ # issue a MAP_REPLACED message.
+ self.port.SetMap(None)
+ self.check_messages([(MAP_REPLACED,)])
+
+ self.clear_messages()
+
+ self.port.SetMap(self.map)
+ self.check_messages([(90.582425142660739, SCALE_CHANGED),
+ (MAP_REPLACED,)])
+
+ def test_changing_map_projection(self):
+ """Test ViewPort behavior when changing the map's projection
+
+ The viewport subscribe's to the map's MAP_PROJECTION_CHANGED
+ messages and tries to adjust the viewport when the projection
+ changes to make sure the map is still visible in the window.
+ There was a bug at one point where the viewport couldn't cope
+ with the map not having a meaningful bounding box in this
+ situation.
+ """
+ # Create a projection and an empty map. We can't use self.map
+ # here because we do need an empty one.
+ themap = Map("title", Projection(["proj=latlong",
+ "to_meter=.017453292519943",
+ "ellps=clrk66"]))
+ # Add the map to self.session so that it's properly destroyed in
+ # tearDown()
+ self.session.AddMap(themap)
+
+ # Add the map to the view port and clear the messages. Then
+ # we're set for the actual test.
+ self.port.SetMap(themap)
+ self.clear_messages()
+
+ # The test: set another projection. The viewport tries to
+ # adjust the view so that the currently visible region stays
+ # visible. The viewport has to take into account that the map
+ # is empty, which it didn't in Thuban/UI/viewport.py rev <= 1.16.
+ # This part of the test is OK when the SetProjection call does
+ # not lead to an exception.
+ themap.SetProjection(Projection(["proj=latlong",
+ "to_meter=.017453292519943",
+ "ellps=clrk66"]))
+
+ # If the map weren't empty the viewport might send SCALE_CHANGED
+ # messages, but it must no do so in this case because the scale
+ # doesn't change.
+ self.check_messages([])
+
+ def testFitRectToWindow(self):
+ rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
+ self.port.FitRectToWindow(rect)
+ self.assertFloatSeqEqual(rect, self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0), 1e-1)
+
+ def testZoomFactor(self):
+ self.port.FitMapToWindow()
+ rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
+ proj_rect = self.port.win_to_proj(0,1000)+self.port.win_to_proj(1000,0)
+ self.port.ZoomFactor(2)
+ self.port.ZoomFactor(.5)
+ self.assertFloatSeqEqual(rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0), 1)
+
+ point = self.port.win_to_proj(600, 600)
+ self.port.ZoomFactor(2, (600, 600))
+ self.assertFloatSeqEqual(point, self.port.win_to_proj(500, 500), 1e-3)
+ self.port.FitMapToWindow()
+
+ proj_rect = self.port.win_to_proj(-499, 1499)\
+ + self.port.win_to_proj(1499, -499)
+ self.port.ZoomFactor(.5)
+ self.assertFloatSeqEqual(proj_rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0), 1)
+
+ def testZoomOutToRect(self):
+ self.port.FitMapToWindow()
+ rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
+ rectTo = self.port.win_to_proj(0, 1000) + self.port.win_to_proj(1000,
+ 0)
+ self.port.ZoomOutToRect(rect)
+ self.assertFloatSeqEqual(rect, rectTo, 1)
+
+ def testTranslate(self):
+ self.port.FitMapToWindow()
+ orig_rect = self.port.win_to_proj(0,1000)+self.port.win_to_proj(1000,0)
+ for delta in [(0, 0), (5, 0), (0, 5), (5,5),
+ (-5, 0), (0, -5), (-5, -5)]:
+ rect = self.port.win_to_proj(0 + delta[0], 1000 + delta[1]) \
+ + self.port.win_to_proj(1000 + delta[0], 0 + delta[1])
+ self.port.Translate(delta[0], delta[1])
+ self.assertFloatSeqEqual(rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0), 1)
+ self.port.Translate(-delta[0], -delta[1])
+ self.assertFloatSeqEqual(rect, orig_rect, 1)
+
+ def test_unprojected_rect_around_point(self):
+ rect = self.port.unprojected_rect_around_point(500, 500, 5)
+ self.assertFloatSeqEqual(rect,
+ (-19.063379161960469, 64.924498140752377,
+ -18.95455127948528, 65.033326023227573),
+ 1e-1)
+
+ def test_find_shape_at(self):
+ eq = self.assertEquals
+ x, y = self.port.proj_to_win(-18, 64.81418571)
+ eq(self.port.find_shape_at(x, y, searched_layer=self.layer),
+ (None, None))
+
+ x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
+ eq(self.port.find_shape_at(x, y, searched_layer=self.layer),
+ (self.layer, 610))
+
+ def testLabelShapeAt(self):
+ eq = self.assertEquals
+
+ # select a road
+ x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
+ eq(self.port.LabelShapeAt(x, y), False) # nothing to do
+ eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
+ eq(self.port.LabelShapeAt(x, y), True) # remove
+
+ # select a point
+ x, y = self.port.proj_to_win(-19.140, 63.4055717)
+ eq(self.port.LabelShapeAt(x, y), False) # nothing to do
+ eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
+ eq(self.port.LabelShapeAt(x, y), True) # remove
+
+ # select a polygon
+ x, y = self.port.proj_to_win(-16.75286628, 64.67807745)
+ eq(self.port.LabelShapeAt(x, y), False) # nothing to do
+ eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
+ # for polygons the coordinates will be different, so
+ # these numbers were copied
+ x, y = self.port.proj_to_win(-18.5939850348, 64.990607973)
+ eq(self.port.LabelShapeAt(x, y), True) # remove
+
+
+ def test_set_pos(self):
+ eq = self.assertEquals
+ # set_current_position / CurrentPosition
+ event = Event()
+ event.m_x, event.m_y = 5, 5
+ self.port.set_current_position(event)
+ eq(self.port.current_position, (5, 5))
+ eq(self.port.CurrentPosition(), self.port.win_to_proj(5, 5))
+ self.port.set_current_position(None)
+ eq(self.port.current_position, None)
+ eq(self.port.CurrentPosition(), None)
+
+ event.m_x, event.m_y = 15, 15
+ self.port.MouseMove(event)
+ eq(self.port.current_position, (15, 15))
+ event.m_x, event.m_y = 25, 15
+ self.port.MouseLeftDown(event)
+ eq(self.port.current_position, (25, 15))
+ event.m_x, event.m_y = 15, 25
+ self.port.MouseLeftUp(event)
+ eq(self.port.current_position, (15, 25))
+
+ def testTools(self):
+ eq = self.assertEquals
+ event = Event()
+ def test_tools(tool, shortcut):
+ self.port.SelectTool(tool)
+ eq(self.port.CurrentTool(), tool.Name())
+ self.port.SelectTool(None)
+ eq(self.port.CurrentTool(), None)
+ shortcut()
+ eq(self.port.CurrentTool(), tool.Name())
+
+ test_tools(ZoomInTool(self.port), self.port.ZoomInTool)
+
+ point = self.port.win_to_proj(600, 600)
+
+ # one click zoom
+ event.m_x, event.m_y = 600, 600
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ self.port.MouseLeftUp(event)
+ self.assertFloatSeqEqual(point, self.port.win_to_proj(500, 500), 1e-3)
+ self.port.FitMapToWindow()
+
+ # zoom rectangle
+ rect = self.port.win_to_proj(29, 970) + self.port.win_to_proj(970, 29)
+ event.m_x, event.m_y = 29, 29
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ event.m_x, event.m_y = 970, 970
+ self.port.MouseMove(event)
+ self.port.MouseLeftUp(event)
+ self.assertFloatSeqEqual(rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0), 1e-1)
+ self.port.FitMapToWindow()
+
+ test_tools(ZoomOutTool(self.port), self.port.ZoomOutTool)
+
+ # one click zoom out
+ proj_rect = self.port.win_to_proj(-499, 1499) \
+ + self.port.win_to_proj(1499, -499)
+ event.m_x, event.m_y = 500, 500
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ self.port.MouseLeftUp(event)
+ self.assertFloatSeqEqual(proj_rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0),1e-1)
+ self.port.FitMapToWindow()
+
+ # zoom out rectangle
+ rect = self.port.win_to_proj(0, 1000) + self.port.win_to_proj(1000, 0)
+ event.m_x, event.m_y = 29, 29
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ event.m_x, event.m_y = 970, 970
+ self.port.MouseMove(event)
+ self.port.MouseLeftUp(event)
+ self.assertFloatSeqEqual(rect,
+ self.port.win_to_proj(29, 970)
+ + self.port.win_to_proj(970, 29))
+ self.port.FitMapToWindow()
+
+ test_tools(PanTool(self.port), self.port.PanTool)
+
+ rect = self.port.win_to_proj(-25, 975) + self.port.win_to_proj(975,-25)
+ event.m_x, event.m_y = 50, 50
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ event.m_x, event.m_y = 75, 75
+ self.port.MouseMove(event)
+ self.port.MouseLeftUp(event)
+ self.assertFloatSeqEqual(rect,
+ self.port.win_to_proj(0, 1000)
+ + self.port.win_to_proj(1000, 0))
+
+ test_tools(IdentifyTool(self.port), self.port.IdentifyTool)
+
+ event.m_x, event.m_y = self.port.proj_to_win(-18.18776318, 64.81418571)
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ self.port.MouseLeftUp(event)
+ eq(self.port.SelectedShapes(), [610])
+
+ test_tools(LabelTool(self.port), self.port.LabelTool)
+
+ # since adding a label requires use interaction with a dialog
+ # we will insert a label and then only test whether clicking
+ # removes the label
+
+ x, y = self.port.proj_to_win(-19.140, 63.4055717)
+ self.port.LabelShapeAt(x, y, "Hello world")
+ event.m_x, event.m_y = x, y
+ self.port.MouseMove(event)
+ self.port.MouseLeftDown(event)
+ self.port.MouseLeftUp(event)
+ eq(self.port.LabelShapeAt(x, y), False) # should have done nothing
+
+ def test_forwarding_title_changed(self):
+ """Test whether ViewPort forwards the TITLE_CHANGED message of the map
+ """
+ self.map.SetTitle(self.map.Title() + " something to make it different")
+ self.check_messages([(self.map, TITLE_CHANGED)])
+
+
+class TestViewportWithPostGIS(unittest.TestCase):
+
+ def setUp(self):
+ """Start the server and create a database.
+
+ The database name will be stored in self.dbname, the server
+ object in self.server and the db object in self.db.
+ """
+ postgissupport.skip_if_no_postgis()
+ self.server = postgissupport.get_test_server()
+ self.dbref = self.server.get_default_static_data_db()
+ self.dbname = self.dbref.dbname
+ self.session = Session("PostGIS Session")
+ self.db = PostGISConnection(dbname = self.dbname,
+ **self.server.connection_params("user"))
+
+ proj = Projection(["proj=latlong",
+ "to_meter=.017453292519943",
+ "ellps=clrk66"])
+ self.map = Map("title", proj)
+
+ self.port = ViewPort((1001, 1001))
+
+ def tearDown(self):
+ self.session.Destroy()
+ self.port.Destroy()
+ self.map.Destroy()
+ self.map = self.port = None
+
+ def test_find_shape_at_point(self):
+ """Test ViewPort.find_shape_at() with postgis point layer"""
+ layer = Layer("Point",
+ self.session.OpenDBShapeStore(self.db, "landmarks"))
+ prop = layer.GetClassification().GetDefaultGroup().GetProperties()
+ prop.SetFill(Color(0,0,0))
+ self.map.AddLayer(layer)
+
+ self.port.SetMap(self.map)
+
+ x, y = self.port.proj_to_win(-22.54335021, 66.30889129)
+ self.assertEquals(self.port.find_shape_at(x, y), (layer, 1001))
+
+ def test_find_shape_at_arc(self):
+ """Test ViewPort.find_shape_at() with postgis arc layer"""
+ layer = Layer("Arc", self.session.OpenDBShapeStore(self.db, "roads"))
+ self.map.AddLayer(layer)
+
+ self.port.SetMap(self.map)
+
+ x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
+ self.assertEquals(self.port.find_shape_at(x, y), (layer, 610))
+
+ def test_find_shape_at_polygon(self):
+ """Test ViewPort.find_shape_at() with postgis polygon layer"""
+ layer = Layer("Poly",
+ self.session.OpenDBShapeStore(self.db, "political"))
+ prop = layer.GetClassification().GetDefaultGroup().GetProperties()
+ prop.SetFill(Color(0,0,0))
+ self.map.AddLayer(layer)
+
+ self.port.SetMap(self.map)
+
+ x, y = self.port.proj_to_win(-19.78369, 65.1649143)
+ self.assertEquals(self.port.find_shape_at(x, y), (layer, 144))
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_wellknowntext.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_wellknowntext.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_wellknowntext.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,79 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test Thuban.Model.wellknowntext"""
+
+__version__ = "$Revision: 1605 $"
+# $Source$
+# $Id: test_wellknowntext.py 1605 2003-08-19 11:00:40Z bh $
+
+import unittest
+
+import support
+support.initthuban()
+
+from Thuban.Model.wellknowntext import parse_wkt_thuban
+
+
+class TestWKT(unittest.TestCase, support.FloatComparisonMixin):
+
+ def test_point(self):
+ """Test WKT parsing of POINT geometries"""
+ wkt = "SRID=1;POINT(6554860 967048)"
+ self.assertPointListEquals(parse_wkt_thuban(wkt),
+ [[(6554860, 967048)]])
+
+ def test_multilinestring(self):
+ """Test WKT parsing of MULTILINESTRING geometries"""
+ wkt = ("MULTILINESTRING(("
+ "(6489598.51 867720.64,"
+ "6489593.90 867837.42),"
+ "(6489624.12 867714.83,"
+ "6489629.83 867621.31,"
+ "6489616.35 867552.57,"
+ "6489608.31 867507.10),"
+ "(6489902.89 868153.54,"
+ "6489880.85 868167.12,"
+ "6489837.96 868136.41,"
+ "6489788.94 868071.37)))")
+ self.assertPointListEquals(parse_wkt_thuban(wkt),
+ [[(6489598.51, 867720.64),
+ (6489593.90, 867837.42)],
+ [(6489624.12, 867714.83),
+ (6489629.83, 867621.31),
+ (6489616.35, 867552.57),
+ (6489608.31, 867507.10)],
+ [(6489902.89, 868153.54),
+ (6489880.85, 868167.12),
+ (6489837.96, 868136.41),
+ (6489788.94, 868071.37)]])
+
+ def test_polygon(self):
+ """Test WKT parsing of POLYGON geometries"""
+ wkt = ("SRID=1;POLYGON((6545639.323878 961209.599602,"
+ "6545630.08526 961213.426864,6545617.99819 961184.249912,"
+ "6545627.236809 961180.422651,6545639.323878 961209.599602))")
+ self.assertPointListEquals(parse_wkt_thuban(wkt),
+ [[(6545639.323878, 961209.599602),
+ (6545630.08526, 961213.426864),
+ (6545617.99819, 961184.249912),
+ (6545627.236809, 961180.422651),
+ (6545639.323878, 961209.599602)]])
+
+ def test_errors(self):
+ """Test WKT parsing error detection"""
+ # empty strings cause value errors
+ self.assertRaises(ValueError, parse_wkt_thuban, "")
+ # strings with only an SRID cause value errors
+ self.assertRaises(ValueError, parse_wkt_thuban, "SRID=1")
+
+ # Missing parentheses cause value errors
+ self.assertRaises(ValueError, parse_wkt_thuban, "POINT(10 20")
+
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_wxproj.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_wxproj.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_wxproj.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,77 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test cases for wxproj"""
+
+__version__ = "$Revision: 1864 $"
+# $Source$
+# $Id: test_wxproj.py 1864 2003-10-24 17:25:53Z bh $
+
+import os
+import unittest
+
+import support
+support.initthuban()
+
+import shapelib
+from wxproj import shape_centroid
+from Thuban.Model.proj import Projection
+
+
+class TestShapeCentroid(unittest.TestCase, support.FloatComparisonMixin):
+
+ """Test cases for wxproj.shape_centroid()"""
+
+ def setUp(self):
+ filename = os.path.join("..", "Data", "iceland", "political.shp")
+ self.shapefile = shapelib.ShapeFile(filename)
+ self.map_proj = Projection(["proj=utm", "zone=26", "ellps=clrk66"])
+ self.layer_proj = Projection(["proj=latlong",
+ "to_meter=0.017453292519943295",
+ "ellps=clrk66"])
+
+ def test_no_proj(self):
+ """Test shape_centroid without any projections"""
+ self.assertFloatSeqEqual(shape_centroid(self.shapefile.cobject(), 0,
+ None, None,
+ 1, 1, 0, 0),
+ (-22.5514848648, 64.7794567309))
+
+ def test_map_proj(self):
+ """Test shape_centroid with map projection"""
+ self.assertFloatSeqEqual(shape_centroid(self.shapefile.cobject(), 0,
+ self.map_proj, None,
+ 1, 1, 0, 0),
+ (711378, 7191110),
+ epsilon = 1)
+
+ def test_layer_proj(self):
+ """Test shape_centroid with layer projection"""
+ self.assertFloatSeqEqual(shape_centroid(self.shapefile.cobject(), 0,
+ None, self.layer_proj,
+ 1, 1, 0, 0),
+ (-22.5514848648, 64.7794567309))
+
+ def test_both_proj(self):
+ """Test shape_centroid with map and layer projection"""
+ self.assertFloatSeqEqual(shape_centroid(self.shapefile.cobject(), 0,
+ self.map_proj, self.layer_proj,
+ 1, 1, 0, 0),
+ (711378, 7191110),
+ epsilon=1)
+
+ def test_invalid_shape_id(self):
+ """Test shape_centroid without an invalid shape id"""
+ self.assertRaises(ValueError, shape_centroid,
+ self.shapefile.cobject(), -1, None, None,
+ 1, 1, 0, 0)
+ self.assertRaises(ValueError, shape_centroid,
+ self.shapefile.cobject(), 1000000, None, None,
+ 1, 1, 0, 0)
+
+if __name__ == "__main__":
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/test_xmlsupport.py
===================================================================
--- packages/thuban/branches/upstream/current/test/test_xmlsupport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/test_xmlsupport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,103 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""Test for the xmlsupport.py module
+"""
+
+__version__ = "$Revision: 1280 $"
+# $Source$
+# $Id: test_xmlsupport.py 1280 2003-06-20 18:29:16Z bh $
+
+import unittest
+
+import xmlsupport
+import support
+
+class TestValidation(unittest.TestCase, xmlsupport.ValidationTest):
+
+ def test_simple(self):
+ """test xmlsupport validating valid XML
+
+ The test succeeds if validate_data doesn't raise any exception
+ """
+ data = ('<?xml version="1.0" encoding="UTF-8"?>\n'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">\n'
+ '<session title="empty session">\n</session>\n')
+ self.validate_data(data)
+
+ def test_invalid(self):
+ """test xmlsupport validating invalid XML
+
+ The test succeeds if validate_data raises an assertion error
+ """
+ data = ('<?xml version="1.0" encoding="UTF-8"?>\n'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">\n'
+ '<session foo="bar">\n</session>\n')
+ # only really run this test when pyRXP is available
+ if xmlsupport.pyRXP is not None:
+ self.assertRaises(AssertionError, self.validate_data, data)
+
+
+
+class TestEventList(unittest.TestCase):
+
+ """Test cases for sax_eventlist"""
+
+ def test_even_list_simple(self):
+ """Test sax_eventlist on very simple XML"""
+ data = "\n".join(['<?xml version="1.0" encoding="UTF-8"?>'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">'
+ '<session title="single map&layer">'
+ '</session>'])
+
+ self.assertEquals(xmlsupport.sax_eventlist(data = data),
+ [('start', (None, u'session'),
+ [((None, u'title'), u'single map&layer')]),
+ ('end', (None, u'session'))])
+
+ def test_even_list_namespace(self):
+ """Test sax_eventlist on XML with a default namespace"""
+ data = "\n".join(['<?xml version="1.0" encoding="UTF-8"?>'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">'
+ '<session title="single map&layer"'
+ ' xmlns="http://example.com/example.dtd">'
+ '</session>'])
+
+ self.assertEquals(xmlsupport.sax_eventlist(data = data),
+ [('start', (u'http://example.com/example.dtd',
+ u'session'),
+ [((None, u'title'), u'single map&layer')]),
+ ('end', (u'http://example.com/example.dtd',
+ u'session'))])
+
+ def test_even_list_id_normalization(self):
+ """Test sax_eventlist id normalization"""
+ data1 = "\n".join(['<?xml version="1.0" encoding="UTF-8"?>'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">'
+ '<session title="bla">'
+ ' <table id="foo"/>'
+ ' <tableref id="foo"/>'
+ '</session>'])
+
+ data2 = "\n".join(['<?xml version="1.0" encoding="UTF-8"?>'
+ '<!DOCTYPE session SYSTEM "thuban.dtd">'
+ '<session title="bla">'
+ ' <table id="bar"/>'
+ ' <tableref id="bar"/>'
+ '</session>'])
+ ids = [((None, "table"), (None, "id"))]
+ idrefs = [((None, "tableref"), (None, "id"))]
+ self.assertEquals(xmlsupport.sax_eventlist(data = data1, ids = ids,
+ idrefs = idrefs),
+ xmlsupport.sax_eventlist(data = data2, ids = ids,
+ idrefs = idrefs))
+
+if __name__ == "__main__":
+ # Fake the __file__ global because it's needed by a test
+ import sys
+ __file__ = sys.argv[0]
+ support.run_tests()
Added: packages/thuban/branches/upstream/current/test/xmlsupport.py
===================================================================
--- packages/thuban/branches/upstream/current/test/xmlsupport.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/test/xmlsupport.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,171 @@
+# Copyright (C) 2003 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with the software for details.
+
+"""XML support code for the test cases"""
+
+__version__ = "$Revision: 1683 $"
+# $Source$
+# $Id: xmlsupport.py 1683 2003-08-28 15:20:57Z bh $
+
+import sys
+import os
+from StringIO import StringIO
+import xml.sax
+import xml.sax.handler
+from xml.sax import make_parser, ErrorHandler, SAXNotRecognizedException
+
+import support
+
+try:
+ import pyRXP
+except ImportError:
+ pyRXP = None
+
+class ValidationTest:
+
+ """Mix-in class for tests that want to check for validity of XML data"""
+
+ # If true, at least one test case tried to validate XML data but
+ # couldn't because PyRXP is not available
+ validation_attempt_ignored = False
+
+ def validate_data(self, data):
+ """Validate the XML data"""
+ if pyRXP is not None:
+ parser = pyRXP.Parser()
+ try:
+ parser.parse(data, eoCB = self.rxp_eo_cb)
+ except pyRXP.error, val:
+ raise AssertionError, str(val), sys.exc_info()[2]
+ else:
+ ValidationTest.validation_attempt_ignored = True
+
+ def rxp_eo_cb(self, filename):
+ """Resolve an eternal entity
+
+ In the Thuban test cases the only external entities that have to
+ be resolved are the DTDs which now live in the resource
+ directory. So, interpret any filename relative to that
+ directory.
+ """
+ return os.path.join(support.resource_dir(), "XML", filename)
+
+
+#
+# Classes and functions to convert XML to a normalized list
+# representation for comparisons
+#
+
+class SaxEventLister(xml.sax.handler.ContentHandler):
+
+ """Create a normalized list representation containing the SAX events
+
+ The normalization includes the following
+
+ - The attribute dictionary of a staertElement event is converted to
+ a sorted list of (key, value) pairs
+
+ - ID and IDREF attribute values are normalized in such a way that
+ two documents that only use different values for IDs can still
+ lead to the same normalized representation.
+
+ The implementation of this feature assumes that all IDs are
+ defined before they are used. The normalized ID values are of the
+ form 'D<NUM>' where <NUM> is a counter starting with 0, so the
+ first ID value will become 'D0', the second 'D1', etc.
+
+ Which attributes are IDs or IDREFS is defined with the
+ correspoding constructor arguments.
+
+ - Filenames are normalized with os.path.normpath. Which attributes
+ are filenames is defiend with the corresponding constructor
+ argument.
+ """
+
+ def __init__(self, ids = (), idrefs = (), filenames = ()):
+ """Initialize the SaxEventLister
+
+ The ids and idrefs parameters should be lists of (element, attr)
+ pairs where element is the name of an attribute as passed to the
+ startElementNS method and attr is the name of an attribute as
+ used in the mapping passed to startElementNS, so both name and
+ attr usually must include the namespace.
+
+ The filenames parameter should be a sequence of the same form as
+ ids and idrefs identifying the attributes which are filenames
+ that should be normalized.
+ """
+ self.eventlist = []
+ self.ids = ids
+ self.idrefs = idrefs
+ self.idremap = {}
+ self.filenames = filenames
+
+ def startElementNS(self, name, qname, attrs):
+ items = attrs.items()
+ items.sort()
+ for i, (attr, value) in zip(range(len(items)), items):
+ #print '++++'
+ #print self.idremap
+ #print name, attr, value
+ if (name, attr) in self.ids:
+ newid = len(self.idremap)
+ self.idremap[value] = "D" + str(newid)
+ value = self.idremap[value]
+ elif (name, attr) in self.idrefs:
+ value = self.idremap[value]
+ elif (name, attr) in self.filenames:
+ value = os.path.normpath(value)
+ items[i] = (attr, value)
+ #print name, attr, value
+ self.eventlist.append(("start", name, items))
+
+ def endElementNS(self, name, qname):
+ self.eventlist.append(("end", name))
+
+
+def sax_eventlist(data = None, filename = None,
+ ids = (), idrefs = (), filenames = ()):
+ """Return a list of SAX event generated for a given XML source
+
+ The xml source may either be a string with the actual XML, in which
+ case it should be given as the keyword argument data or the name of
+ an xml file given as the keyword argument filename
+ """
+ if filename is not None:
+ data = open(filename).read()
+ handler = SaxEventLister(ids = ids, idrefs = idrefs, filenames = filenames)
+ parser = make_parser()
+ parser.setContentHandler(handler)
+ parser.setErrorHandler(ErrorHandler())
+ parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+
+ #
+ # see comment at the end of Thuban/Model/load.py
+ #
+ try:
+ parser.setFeature(xml.sax.handler.feature_validation, 0)
+ parser.setFeature(xml.sax.handler.feature_external_ges, 0)
+ parser.setFeature(xml.sax.handler.feature_external_pes, 0)
+ except SAXNotRecognizedException:
+ pass
+
+ inpsrc = xml.sax.InputSource()
+ inpsrc.setByteStream(StringIO(data))
+ parser.parse(inpsrc)
+
+ return handler.eventlist
+
+
+def print_summary_message():
+ """Print a summary message about validation tests
+
+ Currently simply print a message about pyRXP not being available if
+ a test case's attempt to validate XML was ignored because of that.
+ """
+ if ValidationTest.validation_attempt_ignored:
+ print "XML validation attempts ignored because pyRXP is not available"
Added: packages/thuban/branches/upstream/current/thuban.py
===================================================================
--- packages/thuban/branches/upstream/current/thuban.py 2007-04-06 11:24:19 UTC (rev 717)
+++ packages/thuban/branches/upstream/current/thuban.py 2007-04-06 11:44:54 UTC (rev 718)
@@ -0,0 +1,37 @@
+#! /usr/bin/python
+
+# Copyright (c) 2001 by Intevation GmbH
+# Authors:
+# Bernhard Herzog <bh at intevation.de>
+#
+# This program is free software under the GPL (>=v2)
+# Read the file COPYING coming with Thuban for details.
+
+import sys, os
+import Thuban
+
+# Put the Lib dir into the path. The Lib dir contains some extra non
+# really Thuban specific Python modules
+thubandir = os.path.join(Thuban.__path__[0], '..')
+dir = os.path.join(thubandir, "Lib")
+if os.path.isdir(dir):
+ sys.path.insert(0, dir)
+
+# win32 gdal support
+if sys.platform == 'win32':
+ # PYTHONPATH update
+ dir = os.path.join(thubandir, "gdal", "pymod")
+ if os.path.isdir(dir):
+ sys.path.append(dir)
+
+ try:
+ import gdal
+ except ImportError:
+ print "Please update your PATH environment variable to include %s\\gdal\\bin" % thubandir
+
+import Thuban.UI.main
+
+# Start Thuban
+Thuban.UI.main.main()
+
+
Property changes on: packages/thuban/branches/upstream/current/thuban.py
___________________________________________________________________
Name: svn:executable
+
More information about the Pkg-grass-devel
mailing list